Added the new Running Scripts widget

This commit is contained in:
Mohammed Nafees 2014-04-02 12:46:57 +05:30
parent 89cb1ad527
commit d85d4fea5d
14 changed files with 920 additions and 339 deletions

View file

@ -4,22 +4,22 @@
<context>
<name>Application</name>
<message>
<location filename="src/Application.cpp" line="1381"/>
<location filename="src/Application.cpp" line="1385"/>
<source>Export Voxels</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/Application.cpp" line="1382"/>
<location filename="src/Application.cpp" line="1386"/>
<source>Sparse Voxel Octree Files (*.svo)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/Application.cpp" line="3623"/>
<location filename="src/Application.cpp" line="3643"/>
<source>Open Script</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/Application.cpp" line="3624"/>
<location filename="src/Application.cpp" line="3644"/>
<source>JavaScript Files (*.js)</source>
<translation type="unfinished"></translation>
</message>
@ -113,18 +113,18 @@
<context>
<name>Menu</name>
<message>
<location filename="src/Menu.cpp" line="456"/>
<location filename="src/Menu.cpp" line="457"/>
<source>Open .ini config file</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/Menu.cpp" line="458"/>
<location filename="src/Menu.cpp" line="470"/>
<location filename="src/Menu.cpp" line="459"/>
<location filename="src/Menu.cpp" line="471"/>
<source>Text files (*.ini)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="src/Menu.cpp" line="468"/>
<location filename="src/Menu.cpp" line="469"/>
<source>Save .ini config file</source>
<translation type="unfinished"></translation>
</message>
@ -158,4 +158,55 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RunningScriptsWidget</name>
<message>
<location filename="ui/runningScriptsWidget.ui" line="14"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="126"/>
<source>Form</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="32"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="127"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Running Scripts&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="48"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="128"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Currently running&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="69"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="129"/>
<source>Reload All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="94"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="130"/>
<source>Stop All</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="114"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="131"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Recently loaded&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="146"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="132"/>
<source>(click a script or use the 1-9 keys to load and run it)</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="ui/runningScriptsWidget.ui" line="236"/>
<location filename="../build/interface/ui_runningScriptsWidget.h" line="134"/>
<source>There are no scripts currently running.</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 11 11" enable-background="new 0 0 11 11" xml:space="preserve">
<polygon fill="#C4C4C4" points="11,1.9 9.2,0 5.5,3.7 1.9,0 0,1.9 3.7,5.5 0,9.2 1.9,11 5.5,7.4 9.2,11 11,9.2 7.4,5.5 "/>
</svg>

After

Width:  |  Height:  |  Size: 564 B

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 19.2 16" enable-background="new 0 0 19.2 16" xml:space="preserve">
<g>
<g>
<path fill="#F9F9F9" d="M13.1,13c-1.1,0.7-2.3,1.1-3.6,1.1c-0.2,0-0.3,0-0.5,0c-0.1,0-0.1,0-0.2,0c-0.1,0-0.3,0-0.4-0.1
c-0.1,0-0.2,0-0.2-0.1c-0.1,0-0.2-0.1-0.4-0.1c-0.1,0-0.1,0-0.2-0.1c-0.1,0-0.3-0.1-0.4-0.2c0,0-0.1,0-0.1,0
c-0.2-0.1-0.3-0.1-0.5-0.2c0,0,0,0,0,0c-0.5-0.3-1-0.6-1.4-1c0,0,0,0,0,0c-0.1-0.1-0.2-0.3-0.4-0.4c0,0,0-0.1-0.1-0.1
C4,10.8,3.5,9.5,3.5,8h1.6L2.6,4.2L0,8h1.6c0,1.7,0.5,3.3,1.4,4.5c0,0,0,0,0,0.1c0.1,0.1,0.2,0.3,0.3,0.4c0,0,0.1,0.1,0.1,0.1
c0.1,0.2,0.3,0.3,0.5,0.5c0,0,0,0,0,0c0.5,0.5,1.1,1,1.8,1.4c0,0,0,0,0.1,0c0.2,0.1,0.4,0.2,0.6,0.3c0,0,0.1,0,0.1,0.1
c0.2,0.1,0.3,0.1,0.5,0.2c0.1,0,0.2,0.1,0.2,0.1c0.2,0,0.3,0.1,0.5,0.1c0.1,0,0.2,0.1,0.3,0.1c0,0,0.1,0,0.1,0
c0.1,0,0.3,0,0.4,0.1c0.1,0,0.1,0,0.2,0c0.3,0,0.5,0,0.8,0c1.6,0,3.2-0.5,4.6-1.5c0.4-0.3,0.5-0.9,0.2-1.3
C14.2,12.8,13.6,12.7,13.1,13z"/>
<path fill="#F9F9F9" d="M17.6,8c0-1.7-0.5-3.2-1.4-4.5c0,0,0,0,0-0.1C16.1,3.3,16,3.1,15.8,3c0,0,0,0,0-0.1c-0.8-1-1.8-1.8-3-2.2
c0,0-0.1,0-0.1,0c-0.2-0.1-0.4-0.1-0.6-0.2c-0.1,0-0.1,0-0.2-0.1c-0.2-0.1-0.3-0.1-0.5-0.1c-0.1,0-0.2,0-0.3-0.1c0,0-0.1,0-0.1,0
c-0.1,0-0.3,0-0.4,0c-0.1,0-0.2,0-0.3,0c-0.2,0-0.4,0-0.6,0c0,0-0.1,0-0.1,0c0,0,0,0,0,0C8,0,6.4,0.5,5,1.4
C4.6,1.8,4.5,2.4,4.8,2.8C5.1,3.2,5.7,3.3,6.1,3c1.1-0.7,2.3-1.1,3.5-1.1c0.2,0,0.4,0,0.5,0c0.1,0,0.1,0,0.2,0
c0.1,0,0.3,0,0.4,0.1c0.1,0,0.1,0,0.2,0c0.1,0,0.3,0.1,0.4,0.1c0,0,0.1,0,0.1,0c0.2,0.1,0.3,0.1,0.5,0.2c0,0,0,0,0,0
c0.9,0.4,1.7,1,2.3,1.7c0,0,0,0,0,0c0.9,1.1,1.4,2.4,1.4,3.9h-1.6l2.6,3.8L19.2,8H17.6z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve">
<rect fill="#F9F9F9" width="14" height="14"/>
</svg>

After

Width:  |  Height:  |  Size: 490 B

View file

@ -1,5 +1,8 @@
<RCC>
<qresource prefix="/">
<file>images/close.svg</file>
<file>images/kill-script.svg</file>
<file>images/reload.svg</file>
<file>images/stop.svg</file>
</qresource>
</RCC>

View file

@ -49,7 +49,7 @@
#include <QXmlStreamReader>
#include <QXmlStreamAttributes>
#include <QMediaPlayer>
#include <QMimeData>
#include <QMimeData>
#include <QMessageBox>
#include <AccountManager.h>
@ -118,7 +118,7 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
if (message.size() > 0) {
QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
QString formattedMessage = QString("[%1] %2\n").arg(dateString).arg(message);
fprintf(stdout, "%s", qPrintable(formattedMessage));
Application::getInstance()->getLogger()->addMessage(qPrintable(formattedMessage));
}
@ -174,23 +174,23 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
{
// read the ApplicationInfo.ini file for Name/Version/Domain information
QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
// set the associated application properties
applicationInfo.beginGroup("INFO");
qDebug() << "[VERSION] Build sequence: " << qPrintable(applicationVersion());
setApplicationName(applicationInfo.value("name").toString());
setApplicationVersion(BUILD_VERSION);
setOrganizationName(applicationInfo.value("organizationName").toString());
setOrganizationDomain(applicationInfo.value("organizationDomain").toString());
QSettings::setDefaultFormat(QSettings::IniFormat);
_myAvatar = _avatarManager.getMyAvatar();
_applicationStartupTime = startup_time;
QFontDatabase::addApplicationFont(Application::resourcesPath() + "styles/Inconsolata.otf");
_window->setWindowTitle("Interface");
@ -205,19 +205,19 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
if (portStr) {
listenPort = atoi(portStr);
}
// start the nodeThread so its event loop is running
_nodeThread->start();
// make sure the node thread is given highest priority
_nodeThread->setPriority(QThread::TimeCriticalPriority);
// put the NodeList and datagram processing on the node thread
NodeList* nodeList = NodeList::createInstance(NodeType::Agent, listenPort);
nodeList->moveToThread(_nodeThread);
_datagramProcessor.moveToThread(_nodeThread);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
connect(&nodeList->getNodeSocket(), SIGNAL(readyRead()), &_datagramProcessor, SLOT(processDatagrams()));
@ -239,20 +239,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
// connect to appropriate slots on AccountManager
AccountManager& accountManager = AccountManager::getInstance();
connect(&accountManager, &AccountManager::authRequired, Menu::getInstance(), &Menu::loginForCurrentDomain);
connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle);
// set the account manager's root URL and trigger a login request if we don't have the access token
accountManager.setAuthURL(DEFAULT_NODE_AUTH_URL);
// once the event loop has started, check and signal for an access token
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
_settings = new QSettings(this);
// Check to see if the user passed in a command line option for loading a local
// Voxel File.
_voxelsFilename = getCmdOption(argc, constArgv, "-i");
@ -266,7 +266,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
<< NodeType::VoxelServer << NodeType::ParticleServer
<< NodeType::MetavoxelServer);
// connect to the packet sent signal of the _voxelEditSender and the _particleEditSender
connect(&_voxelEditSender, &VoxelEditPacketSender::packetSent, this, &Application::packetSent);
connect(&_particleEditSender, &ParticleEditPacketSender::packetSent, this, &Application::packetSent);
@ -276,7 +276,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
silentNodeTimer->moveToThread(_nodeThread);
silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
// send the identity packet for our avatar each second to our avatar mixer
QTimer* identityPacketTimer = new QTimer();
connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket);
@ -324,14 +324,18 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
// Set the sixense filtering
_sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense));
checkVersion();
_overlays.init(_glWidget); // do this before scripts load
LocalVoxelsList::getInstance()->addPersistantTree(DOMAIN_TREE_NAME, _voxels.getTree());
LocalVoxelsList::getInstance()->addPersistantTree(CLIPBOARD_TREE_NAME, &_clipboard);
_window->addDockWidget(Qt::NoDockWidgetArea, _runningScriptsWidget = new RunningScriptsWidget());
_runningScriptsWidget->setRunningScripts(getRunningScripts());
connect(_runningScriptsWidget, &RunningScriptsWidget::stopScriptName, this, &Application::stopScript);
// check first run...
QVariant firstRunValue = _settings->value("firstRun",QVariant(true));
if (firstRunValue.isValid() && firstRunValue.toBool()) {
@ -339,7 +343,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
// clear the scripts, and set out script to our default scripts
clearScriptsBeforeRunning();
loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
_settings->setValue("firstRun",QVariant(false));
} else {
// do this as late as possible so that all required subsystems are inialized
@ -350,31 +354,31 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
Application::~Application() {
qInstallMessageHandler(NULL);
// make sure we don't call the idle timer any more
delete idleTimer;
Menu::getInstance()->saveSettings();
_rearMirrorTools->saveSettings(_settings);
_sharedVoxelSystem.changeTree(new VoxelTree);
if (_voxelImporter) {
_voxelImporter->saveSettings(_settings);
delete _voxelImporter;
}
_settings->sync();
// let the avatar mixer know we're out
MyAvatar::sendKillAvatar();
// ask the datagram processing thread to quit and wait until it is done
_nodeThread->quit();
_nodeThread->wait();
// ask the audio thread to quit and wait until it is done
_audio.thread()->quit();
_audio.thread()->wait();
_voxelProcessor.terminate();
_voxelHideShowThread.terminate();
_voxelEditSender.terminate();
@ -387,9 +391,9 @@ Application::~Application() {
Menu::getInstance()->deleteLater();
_myAvatar = NULL;
delete _glWidget;
AccountManager::getInstance().destroy();
}
@ -581,7 +585,7 @@ void Application::paintGL() {
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
renderRearViewMirror(_mirrorViewRect);
} else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
_rearMirrorTools->render(true);
}
@ -654,10 +658,10 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod
if (type == NodeType::VoxelServer && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
continue;
}
// Perform the broadcast for one type
int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(packet, NodeSet() << type);
// Feed number of bytes to corresponding channel of the bandwidth meter, if any (done otherwise)
BandwidthMeter::ChannelIndex channel;
switch (type) {
@ -676,7 +680,7 @@ void Application::controlledBroadcastToNodes(const QByteArray& packet, const Nod
}
bool Application::event(QEvent* event) {
// handle custom URL
if (event->type() == QEvent::FileOpen) {
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
@ -687,11 +691,11 @@ bool Application::event(QEvent* event) {
if (urlParts.count() > 1) {
// if url has 2 or more parts, the first one is domain name
Menu::getInstance()->goToDomain(urlParts[0]);
// location coordinates
Menu::getInstance()->goToDestination(urlParts[1]);
if (urlParts.count() > 2) {
// location orientation
Menu::getInstance()->goToOrientation(urlParts[2]);
}
@ -701,7 +705,7 @@ bool Application::event(QEvent* event) {
Menu::getInstance()->goToDestination(urlParts[0]);
}
}
return false;
}
return QApplication::event(event);
@ -712,7 +716,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
_keysPressed.insert(event->key());
_controllerScriptingInterface.emitKeyPressEvent(event); // send events to any registered scripts
// if one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface.isKeyCaptured(event)) {
return;
@ -1071,7 +1075,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) {
checkBandwidthMeterClick();
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
checkStatsClick();
}
}
}
}
}
@ -1120,7 +1124,7 @@ void Application::touchBeginEvent(QTouchEvent* event) {
if (_controllerScriptingInterface.isTouchCaptured()) {
return;
}
// put any application specific touch behavior below here..
_lastTouchAvgX = _touchAvgX;
_lastTouchAvgY = _touchAvgY;
@ -1163,13 +1167,13 @@ void Application::dropEvent(QDropEvent *event) {
break;
}
}
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath);
if (snapshotData) {
if (!snapshotData->getDomain().isEmpty()) {
Menu::getInstance()->goToDomain(snapshotData->getDomain());
}
_myAvatar->setPosition(snapshotData->getLocation());
_myAvatar->setOrientation(snapshotData->getOrientation());
} else {
@ -1197,19 +1201,19 @@ void Application::timer() {
}
_fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
_frameCount = 0;
_datagramProcessor.resetCounters();
gettimeofday(&_timerStart, NULL);
// ask the node list to check in with the domain server
NodeList::getInstance()->sendDomainServerCheckIn();
}
void Application::idle() {
@ -1246,11 +1250,11 @@ void Application::idle() {
_idleLoopMeasuredJitter = _idleLoopStdev.getStDev();
_idleLoopStdev.reset();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
_buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData());
}
// After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
idleTimer->start(2);
}
@ -1382,7 +1386,7 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
tr("Sparse Voxel Octree Files (*.svo)"));
QByteArray fileNameAscii = fileNameString.toLocal8Bit();
const char* fileName = fileNameAscii.data();
VoxelTreeElement* selectedNode = _voxels.getTree()->getVoxelAt(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s);
if (selectedNode) {
VoxelTree exportTree;
@ -1396,12 +1400,12 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) {
void Application::importVoxels() {
_importSucceded = false;
if (!_voxelImporter) {
_voxelImporter = new VoxelImporter(_window);
_voxelImporter->loadSettings(_settings);
}
if (!_voxelImporter->exec()) {
qDebug() << "[DEBUG] Import succeeded." << endl;
_importSucceded = true;
@ -1415,7 +1419,7 @@ void Application::importVoxels() {
// restore the main window's active state
_window->activateWindow();
emit importDone();
}
@ -1471,7 +1475,7 @@ void Application::pasteVoxels(const VoxelDetail& sourceVoxel) {
}
pasteVoxelsToOctalCode(octalCodeDestination);
if (calculatedOctCode) {
delete[] calculatedOctCode;
}
@ -1508,9 +1512,9 @@ void Application::init() {
// Cleanup of the original shared tree
_sharedVoxelSystem.init();
_voxelImporter = new VoxelImporter(_window);
_environment.init();
_glowEffect.init();
@ -1552,11 +1556,11 @@ void Application::init() {
_audio.setJitterBufferSamples(Menu::getInstance()->getAudioJitterBufferSamples());
}
qDebug("Loaded settings");
// initialize Visage and Faceshift after loading the menu settings
_faceshift.init();
_visage.init();
// fire off an immediate domain-server check in now that settings are loaded
NodeList::getInstance()->sendDomainServerCheckIn();
@ -1575,20 +1579,20 @@ void Application::init() {
_particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
// connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface
connect(&_particleCollisionSystem,
connect(&_particleCollisionSystem,
SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)),
ScriptEngine::getParticlesScriptingInterface(),
ScriptEngine::getParticlesScriptingInterface(),
SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)));
connect(&_particleCollisionSystem,
connect(&_particleCollisionSystem,
SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)),
ScriptEngine::getParticlesScriptingInterface(),
ScriptEngine::getParticlesScriptingInterface(),
SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)));
_audio.init(_glWidget);
_rearMirrorTools = new RearMirrorTools(_glWidget, _mirrorViewRect, _settings);
connect(_rearMirrorTools, SIGNAL(closeView()), SLOT(closeMirrorView()));
connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
@ -1711,7 +1715,7 @@ void Application::updateMyAvatarLookAtPosition() {
float distance = TREE_SCALE;
if (_myAvatar->getLookAtTargetAvatar() && _myAvatar != _myAvatar->getLookAtTargetAvatar()) {
distance = glm::distance(_mouseRayOrigin,
static_cast<Avatar*>(_myAvatar->getLookAtTargetAvatar())->getHead()->calculateAverageEyePosition());
static_cast<Avatar*>(_myAvatar->getLookAtTargetAvatar())->getHead()->calculateAverageEyePosition());
}
const float FIXED_MIN_EYE_DISTANCE = 0.3f;
float minEyeDistance = FIXED_MIN_EYE_DISTANCE + (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON ? 0.0f :
@ -1724,7 +1728,7 @@ void Application::updateMyAvatarLookAtPosition() {
eyePitch = _faceshift.getEstimatedEyePitch();
eyeYaw = _faceshift.getEstimatedEyeYaw();
trackerActive = true;
} else if (_visage.isActive()) {
eyePitch = _visage.getEstimatedEyePitch();
eyeYaw = _visage.getEstimatedEyeYaw();
@ -1907,9 +1911,9 @@ void Application::update(float deltaTime) {
_particles.update(); // update the particles...
_particleCollisionSystem.update(); // collide the particles...
_overlays.update(deltaTime);
// let external parties know we're updating
emit simulating(deltaTime);
}
@ -1933,7 +1937,7 @@ void Application::updateMyAvatar(float deltaTime) {
// actually need to calculate the view frustum planes to send these details
// to the server.
loadViewFrustum(_myCamera, _viewFrustum);
// Update my voxel servers with my current voxel query...
quint64 now = usecTimestampNow();
quint64 sinceLastQuery = now - _lastQueriedTime;
@ -2209,7 +2213,7 @@ void Application::updateShadowMap() {
}
center = inverseRotation * center;
glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius);
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius);
// stretch out our extents in z so that we get all of the avatars
minima.z -= _viewFrustum.getFarClip() * 0.5f;
@ -2230,7 +2234,7 @@ void Application::updateShadowMap() {
_shadowViewFrustum.setEyeOffsetPosition(glm::vec3());
_shadowViewFrustum.setEyeOffsetOrientation(glm::quat());
_shadowViewFrustum.calculate();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
@ -2285,19 +2289,19 @@ void Application::setupWorldLight() {
QImage Application::renderAvatarBillboard() {
_textureCache.getPrimaryFramebufferObject()->bind();
glDisable(GL_BLEND);
const int BILLBOARD_SIZE = 64;
renderRearViewMirror(QRect(0, _glWidget->height() - BILLBOARD_SIZE, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
glReadPixels(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE, GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
glEnable(GL_BLEND);
_textureCache.getPrimaryFramebufferObject()->release();
return image;
}
@ -2398,7 +2402,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
"Application::displaySide() ... metavoxels...");
_metavoxels.render();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... bucky balls...");
@ -2411,7 +2415,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
"Application::displaySide() ... particles...");
_particles.render();
}
// render the ambient occlusion effect if enabled
if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@ -2455,7 +2459,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
// give external parties a change to hook in
emit renderingInWorldInterface();
// render JS/scriptable overlays
_overlays.render3D();
}
@ -2536,8 +2540,8 @@ void Application::displayOverlay() {
char frameTimer[10];
quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5);
sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000));
int timerBottom =
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
int timerBottom =
(Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
? 80 : 20;
drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT);
@ -2552,7 +2556,7 @@ void Application::displayOverlay() {
void Application::displayStatsBackground(unsigned int rgba, int x, int y, int width, int height) {
glBegin(GL_QUADS);
glColor4f(((rgba >> 24) & 0xff) / 255.0f,
((rgba >> 16) & 0xff) / 255.0f,
((rgba >> 16) & 0xff) / 255.0f,
((rgba >> 8) & 0xff) / 255.0f,
(rgba & 0xff) / 255.0f);
glVertex3f(x, y, 0);
@ -2560,7 +2564,7 @@ void Application::displayStatsBackground(unsigned int rgba, int x, int y, int wi
glVertex3f(x + width, y + height, 0);
glVertex3f(x , y + height, 0);
glEnd();
glColor4f(1, 1, 1, 1);
glColor4f(1, 1, 1, 1);
}
// display expanded or contracted stats
@ -2654,12 +2658,12 @@ void Application::displayStats() {
(float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) /
(float)_audio.getNetworkSampleRate() * 1000.f);
drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT);
char audioPing[30];
sprintf(audioPing, "Audio ping: %d", pingAudio);
char avatarPing[30];
sprintf(avatarPing, "Avatar ping: %d", pingAvatar);
char voxelAvgPing[30];
@ -2697,7 +2701,7 @@ void Application::displayStats() {
} else {
// longhand way
sprintf(avatarPosition, "Position: %.1f, %.1f, %.1f", avatarPos.x, avatarPos.y, avatarPos.z);
}
}
char avatarVelocity[30];
sprintf(avatarVelocity, "Velocity: %.1f", glm::length(_myAvatar->getVelocity()));
char avatarBodyYaw[30];
@ -2723,7 +2727,7 @@ void Application::displayStats() {
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT);
stringstream downloadStats;
downloadStats << "Downloads: ";
foreach (Resource* resource, ResourceCache::getLoadingRequests()) {
@ -2731,7 +2735,7 @@ void Application::displayStats() {
downloadStats << roundf(resource->getProgress() * MAXIMUM_PERCENTAGE) << "% ";
}
downloadStats << "(" << ResourceCache::getPendingRequestCount() << " pending)";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloadStats.str().c_str(), WHITE_TEXT);
}
@ -2751,7 +2755,7 @@ void Application::displayStats() {
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
voxelStats.str("");
voxelStats <<
voxelStats <<
"Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB / " <<
"VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB";
if (_voxels.hasVoxelMemoryUsageGPU()) {
@ -2803,7 +2807,7 @@ void Application::displayStats() {
totalNodes += stats.getTotalElements();
if (_statsExpanded) {
totalInternal += stats.getTotalInternal();
totalLeaves += stats.getTotalLeaves();
totalLeaves += stats.getTotalLeaves();
}
}
if (_statsExpanded) {
@ -2827,7 +2831,7 @@ void Application::displayStats() {
QString packetsString = locale.toString((int)voxelPacketsToProcess);
QString maxString = locale.toString((int)_recentMaxPackets);
voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString)
<< " [Recent Max: " << qPrintable(maxString) << "]";
<< " [Recent Max: " << qPrintable(maxString) << "]";
verticalOffset += STATS_PELS_PER_LINE;
drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
}
@ -2989,12 +2993,12 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
_mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees
_mirrorCamera.setDistance(BILLBOARD_DISTANCE * _myAvatar->getScale());
_mirrorCamera.setTargetPosition(_myAvatar->getPosition());
} else if (_rearMirrorTools->getZoomLevel() == BODY) {
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
} else { // HEAD zoom level
_mirrorCamera.setFieldOfView(MIRROR_FIELD_OF_VIEW); // degrees
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
@ -3009,7 +3013,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
}
}
_mirrorCamera.setAspectRatio((float)region.width() / region.height());
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
_mirrorCamera.update(1.0f/_fps);
@ -3054,7 +3058,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) {
if (!billboard) {
_rearMirrorTools->render(false);
}
// reset Viewport and projection matrix
glViewport(0, 0, _glWidget->width(), _glWidget->height());
glDisable(GL_SCISSOR_TEST);
@ -3274,14 +3278,14 @@ void Application::setMenuShortcutsEnabled(bool enabled) {
}
void Application::updateWindowTitle(){
QString buildVersion = " (build " + applicationVersion() + ")";
NodeList* nodeList = NodeList::getInstance();
QString username = AccountManager::getInstance().getUsername();
QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()
+ " @ " + nodeList->getDomainInfo().getHostname() + buildVersion;
qDebug("Application title set to: %s", title.toStdString().c_str());
_window->setWindowTitle(title);
}
@ -3296,7 +3300,7 @@ void Application::domainChanged(const QString& domainHostname) {
_voxelServerJurisdictions.clear();
_octreeServerSceneStats.clear();
_particleServerJurisdictions.clear();
// reset the particle renderer
_particles.clear();
@ -3306,12 +3310,12 @@ void Application::domainChanged(const QString& domainHostname) {
void Application::connectedToDomain(const QString& hostname) {
AccountManager& accountManager = AccountManager::getInstance();
if (accountManager.isLoggedIn()) {
// update our domain-server with the data-server we're logged in with
QString domainPutJsonString = "{\"address\":{\"domain\":\"" + hostname + "\"}}";
accountManager.authenticatedRequest("/api/v1/users/address", QNetworkAccessManager::PutOperation,
JSONCallbackParameters(), domainPutJsonString.toUtf8());
}
@ -3476,13 +3480,13 @@ void Application::loadScripts() {
// loads all saved scripts
QSettings* settings = new QSettings(this);
int size = settings->beginReadArray("Settings");
for (int i = 0; i < size; ++i){
settings->setArrayIndex(i);
QString string = settings->value("script").toString();
loadScript(string);
}
settings->endArray();
}
@ -3497,42 +3501,72 @@ void Application::saveScripts() {
// saves all current running scripts
QSettings* settings = new QSettings(this);
settings->beginWriteArray("Settings");
for (int i = 0; i < _activeScripts.size(); ++i){
for (int i = 0; i < getRunningScripts().size(); ++i){
settings->setArrayIndex(i);
settings->setValue("script", _activeScripts.at(i));
settings->setValue("script", getRunningScripts().at(i));
}
settings->endArray();
}
void Application::stopAllScripts() {
// stops all current running scripts
QList<QAction*> scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions();
foreach (QAction* scriptAction, scriptActions) {
scriptAction->activate(QAction::Trigger);
qDebug() << "stopping script..." << scriptAction->text();
for (int i = 0; i < _scriptEnginesHash.size(); ++i) {
_scriptEnginesHash.values().at(i)->stop();
qDebug() << "stopping script..." << getRunningScripts().at(i);
}
_activeScripts.clear();
_scriptEnginesHash.clear();
_runningScriptsWidget->setRunningScripts(getRunningScripts());
}
void Application::stopScript(const QString &scriptName)
{
_scriptEnginesHash.value(scriptName)->stop();
qDebug() << "stopping script..." << scriptName;
_scriptEnginesHash.remove(scriptName);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
}
void Application::reloadAllScripts() {
// remember all the current scripts so we can reload them
QStringList reloadList = _activeScripts;
QStringList reloadList = getRunningScripts();
// reloads all current running scripts
QList<QAction*> scriptActions = Menu::getInstance()->getActiveScriptsMenu()->actions();
foreach (QAction* scriptAction, scriptActions) {
scriptAction->activate(QAction::Trigger);
qDebug() << "stopping script..." << scriptAction->text();
}
stopAllScripts();
// NOTE: we don't need to clear the _activeScripts list because that is handled on script shutdown.
foreach (QString scriptName, reloadList){
qDebug() << "reloading script..." << scriptName;
loadScript(scriptName);
}
}
void Application::toggleRunningScriptsWidget()
{
if (!_runningScriptsWidget->toggleViewAction()->isChecked()) {
_runningScriptsWidget->move(_window->geometry().topLeft().x(), _window->geometry().topLeft().y());
_runningScriptsWidget->resize(0, _window->height());
_runningScriptsWidget->toggleViewAction()->trigger();
_runningScriptsWidget->grabKeyboard();
QPropertyAnimation* slideAnimation = new QPropertyAnimation(_runningScriptsWidget, "geometry", _runningScriptsWidget);
slideAnimation->setStartValue(_runningScriptsWidget->geometry());
slideAnimation->setEndValue(QRect(_window->geometry().topLeft().x(), _window->geometry().topLeft().y(),
310, _runningScriptsWidget->height()));
slideAnimation->setDuration(250);
slideAnimation->start(QAbstractAnimation::DeleteWhenStopped);
} else {
_runningScriptsWidget->releaseKeyboard();
QPropertyAnimation* slideAnimation = new QPropertyAnimation(_runningScriptsWidget, "geometry", _runningScriptsWidget);
slideAnimation->setStartValue(_runningScriptsWidget->geometry());
slideAnimation->setEndValue(QRect(_window->geometry().topLeft().x(), _window->geometry().topLeft().y(),
0, _runningScriptsWidget->height()));
slideAnimation->setDuration(250);
slideAnimation->start(QAbstractAnimation::DeleteWhenStopped);
QTimer::singleShot(260, _runningScriptsWidget->toggleViewAction(), SLOT(trigger()));
}
}
void Application::uploadFST() {
FstReader reader;
if (reader.zip()) {
@ -3540,29 +3574,17 @@ void Application::uploadFST() {
}
}
void Application::removeScriptName(const QString& fileNameString) {
_activeScripts.removeOne(fileNameString);
}
void Application::cleanupScriptMenuItem(const QString& scriptMenuName) {
Menu::getInstance()->removeAction(Menu::getInstance()->getActiveScriptsMenu(), scriptMenuName);
}
void Application::loadScript(const QString& scriptName) {
// start the script on a new thread...
bool wantMenuItems = true; // tells the ScriptEngine object to add menu items for itself
ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), wantMenuItems, &_controllerScriptingInterface);
ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface);
_scriptEnginesHash.insert(scriptName, scriptEngine);
if (!scriptEngine->hasScript()) {
qDebug() << "Application::loadScript(), script failed to load...";
return;
}
_activeScripts.append(scriptName);
// add a stop menu item
Menu::getInstance()->addActionToQMenuAndActionHash(Menu::getInstance()->getActiveScriptsMenu(),
scriptEngine->getScriptMenuName(), 0, scriptEngine, SLOT(stop()));
_runningScriptsWidget->setRunningScripts(getRunningScripts());
// setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so
// we can use the same ones from the application.
@ -3570,7 +3592,7 @@ void Application::loadScript(const QString& scriptName) {
scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
// hook our avatar object into this script engine
scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features
@ -3595,8 +3617,6 @@ void Application::loadScript(const QString& scriptName) {
// when the thread is terminated, add both scriptEngine and thread to the deleteLater queue
connect(scriptEngine, SIGNAL(finished(const QString&)), scriptEngine, SLOT(deleteLater()));
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(removeScriptName(const QString&)));
connect(scriptEngine, SIGNAL(cleanupMenuItem(const QString&)), this, SLOT(cleanupScriptMenuItem(const QString&)));
// when the application is about to quit, stop our script engine so it unwinds properly
connect(this, SIGNAL(aboutToQuit()), scriptEngine, SLOT(stop()));
@ -3620,12 +3640,12 @@ void Application::loadDialog() {
suggestedName = _previousScriptLocation;
}
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Open Script"), suggestedName,
tr("JavaScript Files (*.js)"));
if (!fileNameString.isEmpty()) {
_previousScriptLocation = fileNameString;
}
loadScript(fileNameString);
}
@ -3636,7 +3656,7 @@ void Application::loadScriptURLDialog() {
scriptURLDialog.setLabelText("Script:");
scriptURLDialog.setWindowFlags(Qt::Sheet);
const float DIALOG_RATIO_OF_WINDOW = 0.30f;
scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
scriptURLDialog.resize(scriptURLDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW,
scriptURLDialog.size().height());
int dialogReturn = scriptURLDialog.exec();
@ -3674,29 +3694,29 @@ void Application::checkVersion() {
}
void Application::parseVersionXml() {
#ifdef Q_OS_WIN32
QString operatingSystem("win");
#endif
#ifdef Q_OS_MAC
QString operatingSystem("mac");
#endif
#ifdef Q_OS_LINUX
QString operatingSystem("ubuntu");
#endif
QString releaseDate;
QString releaseNotes;
QString latestVersion;
QUrl downloadUrl;
QObject* sender = QObject::sender();
QXmlStreamReader xml(qobject_cast<QNetworkReply*>(sender));
while (!xml.atEnd() && !xml.hasError()) {
QXmlStreamReader::TokenType token = xml.readNext();
if (token == QXmlStreamReader::StartElement) {
if (xml.name() == "ReleaseDate") {
xml.readNext();

View file

@ -21,6 +21,7 @@
#include <QSet>
#include <QStringList>
#include <QPointer>
#include <QHash>
#include <NetworkPacket.h>
#include <NodeList.h>
@ -65,6 +66,7 @@
#include "ui/LogDialog.h"
#include "ui/UpdateDialog.h"
#include "ui/overlays/Overlays.h"
#include "ui/RunningScriptsWidget.h"
#include "voxels/VoxelFade.h"
#include "voxels/VoxelHideShowThread.h"
#include "voxels/VoxelImporter.h"
@ -112,7 +114,7 @@ public:
~Application();
void restoreSizeAndPosition();
void loadScript(const QString& fileNameString);
void loadScript(const QString& fileNameString);
void loadScripts();
void storeSizeAndPosition();
void clearScriptsBeforeRunning();
@ -136,9 +138,9 @@ public:
void wheelEvent(QWheelEvent* event);
void dropEvent(QDropEvent *event);
bool event(QEvent* event);
void makeVoxel(glm::vec3 position,
float scale,
unsigned char red,
@ -226,6 +228,8 @@ public:
void skipVersion(QString latestVersion);
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); }
signals:
/// Fired when we're simulating; allows external parties to hook in.
@ -233,10 +237,10 @@ signals:
/// Fired when we're rendering in-world interface elements; allows external parties to hook in.
void renderingInWorldInterface();
/// Fired when the import window is closed
void importDone();
public slots:
void domainChanged(const QString& domainHostname);
void updateWindowTitle();
@ -259,31 +263,30 @@ public slots:
void toggleLogDialog();
void initAvatarAndViewFrustum();
void stopAllScripts();
void stopScript(const QString& scriptName);
void reloadAllScripts();
void toggleRunningScriptsWidget();
void uploadFST();
private slots:
void timer();
void idle();
void connectedToDomain(const QString& hostname);
void setFullscreen(bool fullscreen);
void setEnable3DTVMode(bool enable3DTVMode);
void cameraMenuChanged();
glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint);
void closeMirrorView();
void restoreMirrorView();
void shrinkMirrorView();
void resetSensors();
void parseVersionXml();
void removeScriptName(const QString& fileNameString);
void cleanupScriptMenuItem(const QString& scriptMenuName);
void parseVersionXml();
private:
void resetCamerasOnResizeGL(Camera& camera, int width, int height);
@ -354,7 +357,7 @@ private:
bool _statsExpanded;
BandwidthMeter _bandwidthMeter;
QThread* _nodeThread;
DatagramProcessor _datagramProcessor;
@ -373,7 +376,7 @@ private:
timeval _lastTimeUpdated;
bool _justStarted;
Stars _stars;
BuckyBalls _buckyBalls;
VoxelSystem _voxels;
@ -407,7 +410,6 @@ private:
Visage _visage;
SixenseManager _sixenseManager;
QStringList _activeScripts;
Camera _myCamera; // My view onto the world
Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode
@ -491,10 +493,13 @@ private:
void displayUpdateDialog();
bool shouldSkipVersion(QString latestVersion);
void takeSnapshot();
TouchEvent _lastTouchEvent;
Overlays _overlays;
QPointer<RunningScriptsWidget> _runningScriptsWidget;
QHash<QString, ScriptEngine*> _scriptEnginesHash;
};
#endif /* defined(__interface__Application__) */

View file

@ -87,7 +87,7 @@ Menu::Menu() :
_loginAction(NULL)
{
Application *appInstance = Application::getInstance();
QMenu* fileMenu = addMenu("File");
#ifdef Q_OS_MAC
@ -100,23 +100,24 @@ Menu::Menu() :
#endif
AccountManager& accountManager = AccountManager::getInstance();
_loginAction = addActionToQMenuAndActionHash(fileMenu, MenuOption::Logout);
// call our toggle login function now so the menu option is setup properly
toggleLoginMenuItem();
// connect to the appropriate slots of the AccountManager so that we can change the Login/Logout menu item
connect(&accountManager, &AccountManager::accessTokenChanged, this, &Menu::toggleLoginMenuItem);
connect(&accountManager, &AccountManager::logoutComplete, this, &Menu::toggleLoginMenuItem);
addDisabledActionAndSeparator(fileMenu, "Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScript, Qt::CTRL | Qt::Key_O, appInstance, SLOT(loadDialog()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
addActionToQMenuAndActionHash(fileMenu, MenuOption::LoadScriptURL,
Qt::CTRL | Qt::SHIFT | Qt::Key_O, appInstance, SLOT(loadScriptURLDialog()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::StopAllScripts, 0, appInstance, SLOT(stopAllScripts()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::ReloadAllScripts, 0, appInstance, SLOT(reloadAllScripts()));
_activeScriptsMenu = fileMenu->addMenu("Running Scripts");
addActionToQMenuAndActionHash(fileMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J,
appInstance, SLOT(toggleRunningScriptsWidget()));
addDisabledActionAndSeparator(fileMenu, "Go");
addActionToQMenuAndActionHash(fileMenu,
@ -147,7 +148,7 @@ Menu::Menu() :
addDisabledActionAndSeparator(fileMenu, "Upload Avatar Model");
addActionToQMenuAndActionHash(fileMenu, MenuOption::UploadFST, 0, Application::getInstance(), SLOT(uploadFST()));
addDisabledActionAndSeparator(fileMenu, "Settings");
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsImport, 0, this, SLOT(importSettings()));
addActionToQMenuAndActionHash(fileMenu, MenuOption::SettingsExport, 0, this, SLOT(exportSettings()));
@ -172,8 +173,8 @@ Menu::Menu() :
addDisabledActionAndSeparator(editMenu, "Physics");
addCheckableActionToQMenuAndActionHash(editMenu, MenuOption::Gravity, Qt::SHIFT | Qt::Key_G, false);
addAvatarCollisionSubMenu(editMenu);
@ -207,7 +208,7 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
appInstance, SLOT(cameraMenuChanged()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Enable3DTVMode, 0,
false,
appInstance,
@ -333,16 +334,16 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings, Qt::CTRL | Qt::SHIFT | Qt::Key_P);
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings, Qt::CTRL | Qt::SHIFT | Qt::Key_S);
addCheckableActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::CullSharedFaces,
Qt::CTRL | Qt::SHIFT | Qt::Key_C,
addCheckableActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::CullSharedFaces,
Qt::CTRL | Qt::SHIFT | Qt::Key_C,
false,
appInstance->getVoxels(),
SLOT(cullSharedFaces()));
addCheckableActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::ShowCulledSharedFaces,
Qt::CTRL | Qt::SHIFT | Qt::Key_X,
addCheckableActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::ShowCulledSharedFaces,
Qt::CTRL | Qt::SHIFT | Qt::Key_X,
false,
appInstance->getVoxels(),
SLOT(showCulledSharedFaces()));
@ -360,14 +361,14 @@ Menu::Menu() :
false,
appInstance->getAudio(),
SLOT(toggleMute()));
addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel,
Qt::CTRL | Qt::SHIFT | Qt::Key_V,
this,
SLOT(pasteToVoxel()));
connect(appInstance->getAudio(), SIGNAL(muteToggled()), this, SLOT(audioMuteToggled()));
#ifndef Q_OS_MAC
QMenu* helpMenu = addMenu("Help");
QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp);
@ -571,7 +572,7 @@ void Menu::addDisabledActionAndSeparator(QMenu* destinationMenu, const QString&
QAction* separatorText = new QAction(actionName,destinationMenu);
separatorText->setEnabled(false);
destinationMenu->insertAction(actionBefore, separatorText);
} else {
destinationMenu->addSeparator();
(destinationMenu->addAction(actionName))->setEnabled(false);
@ -623,7 +624,7 @@ QAction* Menu::addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
const char* member,
int menuItemLocation) {
QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member,
QAction* action = addActionToQMenuAndActionHash(destinationMenu, actionName, shortcut, receiver, member,
QAction::NoRole, menuItemLocation);
action->setCheckable(true);
action->setChecked(checked);
@ -677,35 +678,35 @@ const float DIALOG_RATIO_OF_WINDOW = 0.30f;
void Menu::loginForCurrentDomain() {
QDialog loginDialog(Application::getInstance()->getWindow());
loginDialog.setWindowTitle("Login");
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
loginDialog.setLayout(layout);
loginDialog.setWindowFlags(Qt::Sheet);
QFormLayout* form = new QFormLayout();
layout->addLayout(form, 1);
QLineEdit* loginLineEdit = new QLineEdit();
loginLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
form->addRow("Login:", loginLineEdit);
QLineEdit* passwordLineEdit = new QLineEdit();
passwordLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
passwordLineEdit->setEchoMode(QLineEdit::Password);
form->addRow("Password:", passwordLineEdit);
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
loginDialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
loginDialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
layout->addWidget(buttons);
int dialogReturn = loginDialog.exec();
if (dialogReturn == QDialog::Accepted && !loginLineEdit->text().isEmpty() && !passwordLineEdit->text().isEmpty()) {
// attempt to get an access token given this username and password
AccountManager::getInstance().requestAccessToken(loginLineEdit->text(), passwordLineEdit->text());
}
sendFakeEnterEvent();
}
@ -713,19 +714,19 @@ void Menu::editPreferences() {
Application* applicationInstance = Application::getInstance();
ModelBrowser headBrowser(Head);
ModelBrowser skeletonBrowser(Skeleton);
const QString BROWSE_BUTTON_TEXT = "Browse";
QDialog dialog(applicationInstance->getWindow());
dialog.setWindowTitle("Interface Preferences");
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
dialog.setLayout(layout);
QFormLayout* form = new QFormLayout();
layout->addLayout(form, 1);
QHBoxLayout headModelLayout;
QString faceURLString = applicationInstance->getAvatar()->getHead()->getFaceModel().getURL().toString();
QLineEdit headURLEdit(faceURLString);
@ -737,7 +738,7 @@ void Menu::editPreferences() {
headModelLayout.addWidget(&headURLEdit);
headModelLayout.addWidget(&headBrowseButton);
form->addRow("Head URL:", &headModelLayout);
QHBoxLayout skeletonModelLayout;
QString skeletonURLString = applicationInstance->getAvatar()->getSkeletonModel().getURL().toString();
QLineEdit skeletonURLEdit(skeletonURLString);
@ -749,7 +750,7 @@ void Menu::editPreferences() {
skeletonModelLayout.addWidget(&skeletonURLEdit);
skeletonModelLayout.addWidget(&SkeletonBrowseButton);
form->addRow("Skeleton URL:", &skeletonModelLayout);
QString displayNameString = applicationInstance->getAvatar()->getDisplayName();
QLineEdit* displayNameEdit = new QLineEdit(displayNameString);
@ -826,12 +827,12 @@ void Menu::editPreferences() {
}
QString displayNameStr(displayNameEdit->text());
if (displayNameStr != displayNameString) {
applicationInstance->getAvatar()->setDisplayName(displayNameStr);
shouldDispatchIdentityPacket = true;
}
if (shouldDispatchIdentityPacket) {
applicationInstance->getAvatar()->sendIdentityPacket();
}
@ -864,10 +865,10 @@ void Menu::editPreferences() {
void Menu::goToDomain(const QString newDomain) {
if (NodeList::getInstance()->getDomainInfo().getHostname() != newDomain) {
// send a node kill request, indicating to other clients that they should play the "disappeared" effect
Application::getInstance()->getAvatar()->sendKillAvatar();
// give our nodeList the new domain-server hostname
NodeList::getInstance()->getDomainInfo().setHostname(newDomain);
}
@ -897,7 +898,7 @@ void Menu::goToDomainDialog() {
// the user input a new hostname, use that
newHostname = domainDialog.textValue();
}
goToDomain(newHostname);
}
@ -913,7 +914,7 @@ bool Menu::goToDestination(QString destination) {
}
void Menu::goTo() {
QInputDialog gotoDialog(Application::getInstance()->getWindow());
gotoDialog.setWindowTitle("Go to");
gotoDialog.setLabelText("Destination:");
@ -921,7 +922,7 @@ void Menu::goTo() {
gotoDialog.setTextValue(destination);
gotoDialog.setWindowFlags(Qt::Sheet);
gotoDialog.resize(gotoDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, gotoDialog.size().height());
int dialogReturn = gotoDialog.exec();
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
goToUser(gotoDialog.textValue());
@ -1070,7 +1071,7 @@ void Menu::toggleLoginMenuItem() {
AccountManager& accountManager = AccountManager::getInstance();
disconnect(_loginAction, 0, 0, 0);
if (accountManager.isLoggedIn()) {
// change the menu item to logout
_loginAction->setText("Logout " + accountManager.getUsername());
@ -1078,7 +1079,7 @@ void Menu::toggleLoginMenuItem() {
} else {
// change the menu item to login
_loginAction->setText("Login");
connect(_loginAction, &QAction::triggered, this, &Menu::loginForCurrentDomain);
}
}
@ -1185,7 +1186,7 @@ QString Menu::getLODFeedbackText() {
} break;
}
// distance feedback
// distance feedback
float voxelSizeScale = getVoxelSizeScale();
float relativeToDefault = voxelSizeScale / DEFAULT_OCTREE_SIZE_SCALE;
QString result;
@ -1200,7 +1201,7 @@ QString Menu::getLODFeedbackText() {
}
void Menu::autoAdjustLOD(float currentFPS) {
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
// NOTE: our first ~100 samples at app startup are completely all over the place, and we don't
// really want to count them in our average, so we will ignore the real frame rates and stuff
// our moving average with simulated good data
const int IGNORE_THESE_SAMPLES = 100;
@ -1212,7 +1213,7 @@ void Menu::autoAdjustLOD(float currentFPS) {
_fastFPSAverage.updateAverage(currentFPS);
quint64 now = usecTimestampNow();
const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000;
if (_fastFPSAverage.getAverage() < ADJUST_LOD_DOWN_FPS) {
if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) {
@ -1231,11 +1232,11 @@ void Menu::autoAdjustLOD(float currentFPS) {
_avatarLODDistanceMultiplier = qMax(MINIMUM_DISTANCE_MULTIPLIER,
_avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE);
}
bool changed = false;
quint64 elapsed = now - _lastAdjust;
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS
if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS
&& _voxelSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) {
_voxelSizeScale *= ADJUST_LOD_DOWN_BY;
@ -1248,7 +1249,7 @@ void Menu::autoAdjustLOD(float currentFPS) {
<< "_voxelSizeScale=" << _voxelSizeScale;
}
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > ADJUST_LOD_UP_FPS
if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > ADJUST_LOD_UP_FPS
&& _voxelSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) {
_voxelSizeScale *= ADJUST_LOD_UP_BY;
if (_voxelSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) {
@ -1259,7 +1260,7 @@ void Menu::autoAdjustLOD(float currentFPS) {
qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage()
<< "_voxelSizeScale=" << _voxelSizeScale;
}
if (changed) {
if (_lodToolsDialog) {
_lodToolsDialog->reloadSliders();
@ -1337,13 +1338,13 @@ void Menu::addAvatarCollisionSubMenu(QMenu* overMenu) {
Application* appInstance = Application::getInstance();
QObject* avatar = appInstance->getAvatar();
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithEnvironment,
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithEnvironment,
0, false, avatar, SLOT(updateCollisionFlags()));
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithAvatars,
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithAvatars,
0, true, avatar, SLOT(updateCollisionFlags()));
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithVoxels,
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithVoxels,
0, false, avatar, SLOT(updateCollisionFlags()));
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithParticles,
addCheckableActionToQMenuAndActionHash(subMenu, MenuOption::CollideWithParticles,
0, true, avatar, SLOT(updateCollisionFlags()));
}
@ -1352,9 +1353,9 @@ QAction* Menu::getActionFromName(const QString& menuName, QMenu* menu) {
if (menu) {
menuActions = menu->actions();
} else {
menuActions = actions();
menuActions = actions();
}
foreach (QAction* menuAction, menuActions) {
if (menuName == menuAction->text()) {
return menuAction;
@ -1461,7 +1462,7 @@ QMenu* Menu::addMenu(const QString& menuName) {
void Menu::removeMenu(const QString& menuName) {
QAction* action = getMenuAction(menuName);
// only proceed if the menu actually exists
if (action) {
QString finalMenuPart;
@ -1513,7 +1514,7 @@ void Menu::addMenuItem(const MenuItemProperties& properties) {
if (!properties.shortcutKeySequence.isEmpty()) {
shortcut = new QShortcut(properties.shortcutKeySequence, this);
}
// check for positioning requests
int requestedPosition = properties.position;
if (requestedPosition == UNSPECIFIED_POSITION && !properties.beforeItem.isEmpty()) {
@ -1527,13 +1528,13 @@ void Menu::addMenuItem(const MenuItemProperties& properties) {
requestedPosition = afterPosition + 1;
}
}
QAction* menuItemAction = NULL;
if (properties.isSeparator) {
addDisabledActionAndSeparator(menuObj, properties.menuItemName, requestedPosition);
} else if (properties.isCheckable) {
menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName,
properties.shortcutKeySequence, properties.isChecked,
properties.shortcutKeySequence, properties.isChecked,
MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition);
} else {
menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence,

View file

@ -95,8 +95,6 @@ public:
// User Tweakable PPS from Voxel Server
int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; }
QMenu* getActiveScriptsMenu() { return _activeScriptsMenu;}
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
const QString& actionName,
const QKeySequence& shortcut = 0,
@ -124,7 +122,7 @@ public slots:
void goTo();
void goToUser(const QString& user);
void pasteToVoxel();
void toggleLoginMenuItem();
QMenu* addMenu(const QString& menuName);
@ -166,7 +164,7 @@ private:
void scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set);
/// 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,
int menuItemLocation = UNSPECIFIED_POSITION);
QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu,
@ -189,7 +187,7 @@ private:
int findPositionOfMenuItem(QMenu* menu, const QString& searchMenuItem);
int positionBeforeSeparatorIfNeeded(QMenu* menu, int requestedPosition);
QMenu* getMenu(const QString& menuName);
QHash<QString, QAction*> _actionHash;
int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback
@ -208,7 +206,6 @@ private:
int _boundaryLevelAdjust;
QAction* _useVoxelShader;
int _maxVoxelPacketsPerSecond;
QMenu* _activeScriptsMenu;
QString replaceLastOccurrence(QChar search, QChar replace, QString string);
quint64 _lastAdjust;
quint64 _lastAvatarDetailDrop;
@ -290,6 +287,7 @@ namespace MenuOption {
const QString RenderSkeletonCollisionProxies = "Skeleton Collision Proxies";
const QString RenderHeadCollisionProxies = "Head Collision Proxies";
const QString ResetAvatarSize = "Reset Avatar Size";
const QString RunningScripts = "Running Scripts";
const QString RunTimingTests = "Run Timing Tests";
const QString SettingsImport = "Import Settings";
const QString Shadows = "Shadows";

View file

@ -0,0 +1,203 @@
//
// RunningScripts.cpp
// interface
//
// Created by Mohammed Nafees on 03/28/2014.
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
#include "ui_runningScriptsWidget.h"
#include "RunningScriptsWidget.h"
#include <QKeyEvent>
#include <QTableWidgetItem>
#include "Application.h"
RunningScriptsWidget::RunningScriptsWidget(QDockWidget *parent) :
QDockWidget(parent),
ui(new Ui::RunningScriptsWidget)
{
ui->setupUi(this);
// remove the title bar (see the Qt docs on setTitleBarWidget)
setTitleBarWidget(new QWidget());
ui->runningScriptsTableWidget->setColumnCount(2);
ui->runningScriptsTableWidget->verticalHeader()->setVisible(false);
ui->runningScriptsTableWidget->horizontalHeader()->setVisible(false);
ui->runningScriptsTableWidget->setSelectionMode(QAbstractItemView::NoSelection);
ui->runningScriptsTableWidget->setShowGrid(false);
ui->runningScriptsTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->runningScriptsTableWidget->setColumnWidth(0, 235);
ui->runningScriptsTableWidget->setColumnWidth(1, 25);
connect(ui->runningScriptsTableWidget, &QTableWidget::cellClicked, this, &RunningScriptsWidget::stopScript);
ui->recentlyLoadedScriptsTableWidget->setColumnCount(2);
ui->recentlyLoadedScriptsTableWidget->verticalHeader()->setVisible(false);
ui->recentlyLoadedScriptsTableWidget->horizontalHeader()->setVisible(false);
ui->recentlyLoadedScriptsTableWidget->setSelectionMode(QAbstractItemView::NoSelection);
ui->recentlyLoadedScriptsTableWidget->setShowGrid(false);
ui->recentlyLoadedScriptsTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->recentlyLoadedScriptsTableWidget->setColumnWidth(0, 25);
ui->recentlyLoadedScriptsTableWidget->setColumnWidth(1, 235);
connect(ui->recentlyLoadedScriptsTableWidget, &QTableWidget::cellClicked,
this, &RunningScriptsWidget::loadScript);
connect(ui->hideWidgetButton, &QPushButton::clicked,
Application::getInstance(), &Application::toggleRunningScriptsWidget);
connect(ui->reloadAllButton, &QPushButton::clicked,
Application::getInstance(), &Application::reloadAllScripts);
connect(ui->stopAllButton, &QPushButton::clicked,
this, &RunningScriptsWidget::allScriptsStopped);
}
RunningScriptsWidget::~RunningScriptsWidget()
{
delete ui;
}
void RunningScriptsWidget::setRunningScripts(const QStringList& list)
{
ui->runningScriptsTableWidget->setRowCount(list.size());
ui->noRunningScriptsLabel->setVisible(list.isEmpty());
ui->currentlyRunningLabel->setVisible(!list.isEmpty());
ui->line1->setVisible(!list.isEmpty());
ui->runningScriptsTableWidget->setVisible(!list.isEmpty());
ui->reloadAllButton->setVisible(!list.isEmpty());
ui->stopAllButton->setVisible(!list.isEmpty());
for (int i = 0; i < list.size(); ++i) {
QTableWidgetItem *scriptName = new QTableWidgetItem;
scriptName->setText(list.at(i));
scriptName->setToolTip(list.at(i));
scriptName->setTextAlignment(Qt::AlignCenter);
QTableWidgetItem *closeIcon = new QTableWidgetItem;
closeIcon->setIcon(QIcon(":/images/kill-script.svg"));
ui->runningScriptsTableWidget->setItem(i, 0, scriptName);
ui->runningScriptsTableWidget->setItem(i, 1, closeIcon);
}
createRecentlyLoadedScriptsTable();
}
void RunningScriptsWidget::keyPressEvent(QKeyEvent *e)
{
switch(e->key()) {
case Qt::Key_Escape:
Application::getInstance()->toggleRunningScriptsWidget();
break;
case Qt::Key_1:
if (_recentlyLoadedScripts.size() > 0) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(0));
}
break;
case Qt::Key_2:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 2) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(1));
}
break;
case Qt::Key_3:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 3) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(2));
}
break;
case Qt::Key_4:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 4) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(3));
}
break;
case Qt::Key_5:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 5) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(4));
}
break;
case Qt::Key_6:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 6) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(5));
}
break;
case Qt::Key_7:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 7) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(6));
}
break;
case Qt::Key_8:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 8) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(7));
}
break;
case Qt::Key_9:
if (_recentlyLoadedScripts.size() > 0 && _recentlyLoadedScripts.size() >= 9) {
Application::getInstance()->loadScript(_recentlyLoadedScripts.at(8));
}
break;
default:
break;
}
}
void RunningScriptsWidget::stopScript(int row, int column)
{
if (column == 1) { // make sure the user has clicked on the close icon
_lastStoppedScript = ui->runningScriptsTableWidget->item(row, 0)->text();
emit stopScriptName(ui->runningScriptsTableWidget->item(row, 0)->text());
}
}
void RunningScriptsWidget::loadScript(int row, int column)
{
Application::getInstance()->loadScript(ui->recentlyLoadedScriptsTableWidget->item(row, column)->text());
}
void RunningScriptsWidget::allScriptsStopped()
{
QStringList list = Application::getInstance()->getRunningScripts();
for (int i = 0; i < list.size(); ++i) {
_recentlyLoadedScripts.prepend(list.at(i));
}
Application::getInstance()->stopAllScripts();
}
void RunningScriptsWidget::createRecentlyLoadedScriptsTable()
{
if (!_recentlyLoadedScripts.contains(_lastStoppedScript) && !_lastStoppedScript.isEmpty()) {
_recentlyLoadedScripts.prepend(_lastStoppedScript);
_lastStoppedScript = "";
}
for (int i = 0; i < _recentlyLoadedScripts.size(); ++i) {
if (Application::getInstance()->getRunningScripts().contains(_recentlyLoadedScripts.at(i))) {
_recentlyLoadedScripts.removeOne(_recentlyLoadedScripts.at(i));
}
}
ui->recentlyLoadedLabel->setVisible(!_recentlyLoadedScripts.isEmpty());
ui->line2->setVisible(!_recentlyLoadedScripts.isEmpty());
ui->recentlyLoadedScriptsTableWidget->setVisible(!_recentlyLoadedScripts.isEmpty());
ui->recentlyLoadedInstruction->setVisible(!_recentlyLoadedScripts.isEmpty());
int limit = _recentlyLoadedScripts.size() > 9 ? 9 : _recentlyLoadedScripts.size();
ui->recentlyLoadedScriptsTableWidget->setRowCount(limit);
for (int i = 0; i < limit; ++i) {
QTableWidgetItem *scriptName = new QTableWidgetItem;
scriptName->setText(_recentlyLoadedScripts.at(i));
scriptName->setToolTip(_recentlyLoadedScripts.at(i));
scriptName->setTextAlignment(Qt::AlignCenter);
QTableWidgetItem *number = new QTableWidgetItem;
number->setText(QString::number(i+1) + ".");
ui->recentlyLoadedScriptsTableWidget->setItem(i, 0, number);
ui->recentlyLoadedScriptsTableWidget->setItem(i, 1, scriptName);
}
}

View file

@ -0,0 +1,46 @@
//
// RunningScripts.h
// interface
//
// Created by Mohammed Nafees on 03/28/2014.
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
#ifndef __hifi__RunningScriptsWidget__
#define __hifi__RunningScriptsWidget__
// Qt
#include <QDockWidget>
namespace Ui {
class RunningScriptsWidget;
}
class RunningScriptsWidget : public QDockWidget
{
Q_OBJECT
public:
explicit RunningScriptsWidget(QDockWidget *parent = 0);
~RunningScriptsWidget();
void setRunningScripts(const QStringList& list);
signals:
void stopScriptName(QString name);
protected:
void keyPressEvent(QKeyEvent *e);
private slots:
void stopScript(int row, int column);
void loadScript(int row, int column);
void allScriptsStopped();
private:
Ui::RunningScriptsWidget *ui;
QStringList _recentlyLoadedScripts;
QString _lastStoppedScript;
void createRecentlyLoadedScriptsTable();
};
#endif /* defined(__hifi__RunningScriptsWidget__) */

View file

@ -0,0 +1,248 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RunningScriptsWidget</class>
<widget class="QWidget" name="RunningScriptsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>310</width>
<height>651</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<property name="styleSheet">
<string notr="true">background: #f7f7f7;
font-family: Helvetica, Arial, &quot;DejaVu Sans&quot;; </string>
</property>
<widget class="QLabel" name="widgetTitle">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>221</width>
<height>31</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: #0e7077;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:18pt;&quot;&gt;Running Scripts&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QLabel" name="currentlyRunningLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>40</y>
<width>301</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: #0e7077;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Currently running&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QPushButton" name="reloadAllButton">
<property name="geometry">
<rect>
<x>40</x>
<y>230</y>
<width>111</width>
<height>31</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">background: #0e7077;
color: #fff;
border-radius: 6px;</string>
</property>
<property name="text">
<string>Reload All</string>
</property>
<property name="icon">
<iconset resource="../resources/resources.qrc">
<normaloff>:/images/reload.svg</normaloff>:/images/reload.svg</iconset>
</property>
</widget>
<widget class="QPushButton" name="stopAllButton">
<property name="geometry">
<rect>
<x>160</x>
<y>230</y>
<width>101</width>
<height>31</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">background: #0e7077;
color: #fff;
border-radius: 6px;</string>
</property>
<property name="text">
<string>Stop All</string>
</property>
<property name="icon">
<iconset resource="../resources/resources.qrc">
<normaloff>:/images/stop.svg</normaloff>:/images/stop.svg</iconset>
</property>
</widget>
<widget class="QLabel" name="recentlyLoadedLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>280</y>
<width>301</width>
<height>20</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: #0e7077;</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Recently loaded&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="Line" name="line2">
<property name="geometry">
<rect>
<x>20</x>
<y>300</y>
<width>271</width>
<height>8</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QLabel" name="recentlyLoadedInstruction">
<property name="geometry">
<rect>
<x>20</x>
<y>590</y>
<width>271</width>
<height>41</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">color: #95a5a6;</string>
</property>
<property name="text">
<string>(click a script or use the 1-9 keys to load and run it)</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="hideWidgetButton">
<property name="geometry">
<rect>
<x>270</x>
<y>10</y>
<width>31</width>
<height>31</height>
</rect>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/resources.qrc">
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
<widget class="QTableWidget" name="runningScriptsTableWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>70</y>
<width>271</width>
<height>141</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background: transparent;</string>
</property>
</widget>
<widget class="Line" name="line1">
<property name="geometry">
<rect>
<x>20</x>
<y>60</y>
<width>271</width>
<height>8</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QTableWidget" name="recentlyLoadedScriptsTableWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>310</y>
<width>271</width>
<height>281</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background: transparent;</string>
</property>
</widget>
<widget class="QLabel" name="noRunningScriptsLabel">
<property name="geometry">
<rect>
<x>20</x>
<y>40</y>
<width>271</width>
<height>51</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">font: 14px;</string>
</property>
<property name="text">
<string>There are no scripts currently running.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</widget>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -29,7 +29,6 @@
#include "LocalVoxels.h"
#include "ScriptEngine.h"
int ScriptEngine::_scriptNumber = 1;
VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface;
ParticlesScriptingInterface ScriptEngine::_particlesScriptingInterface;
@ -41,7 +40,7 @@ static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* eng
}
ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, const QString& fileNameString,
ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
_scriptContents(scriptContents),
@ -58,26 +57,15 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, bool wantMenuItems, co
_numAvatarSoundSentBytes(0),
_controllerScriptingInterface(controllerScriptingInterface),
_avatarData(NULL),
_wantMenuItems(wantMenuItems),
_scriptMenuName(),
_scriptName(),
_fileNameString(fileNameString),
_quatLibrary(),
_vec3Library()
{
// some clients will use these menu features
if (!fileNameString.isEmpty()) {
_scriptMenuName = "Stop ";
_scriptMenuName.append(qPrintable(fileNameString));
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
} else {
_scriptMenuName = "Stop Script ";
_scriptMenuName.append(_scriptNumber);
}
_scriptNumber++;
}
ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
ScriptEngine::ScriptEngine(const QUrl& scriptURL,
AbstractControllerScriptingInterface* controllerScriptingInterface) :
_scriptContents(),
_isFinished(false),
_isRunning(false),
@ -92,32 +80,21 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems,
_numAvatarSoundSentBytes(0),
_controllerScriptingInterface(controllerScriptingInterface),
_avatarData(NULL),
_wantMenuItems(wantMenuItems),
_scriptMenuName(),
_scriptName(),
_fileNameString(),
_quatLibrary(),
_vec3Library()
{
QString scriptURLString = scriptURL.toString();
_fileNameString = scriptURLString;
// some clients will use these menu features
if (!scriptURLString.isEmpty()) {
_scriptMenuName = "Stop ";
_scriptMenuName.append(qPrintable(scriptURLString));
_scriptMenuName.append(QString(" [%1]").arg(_scriptNumber));
} else {
_scriptMenuName = "Stop Script ";
_scriptMenuName.append(_scriptNumber);
}
_scriptNumber++;
QUrl url(scriptURL);
// if the scheme is empty, maybe they typed in a file, let's try
if (url.scheme().isEmpty()) {
url = QUrl::fromLocalFile(scriptURLString);
}
// ok, let's see if it's valid... and if so, load it
if (url.isValid()) {
if (url.scheme() == "file") {
@ -144,16 +121,16 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL, bool wantMenuItems,
void ScriptEngine::setIsAvatar(bool isAvatar) {
_isAvatar = isAvatar;
if (_isAvatar && !_avatarIdentityTimer) {
// set up the avatar timers
_avatarIdentityTimer = new QTimer(this);
_avatarBillboardTimer = new QTimer(this);
// connect our slot
connect(_avatarIdentityTimer, &QTimer::timeout, this, &ScriptEngine::sendAvatarIdentityPacket);
connect(_avatarBillboardTimer, &QTimer::timeout, this, &ScriptEngine::sendAvatarBillboardPacket);
// start the timers
_avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS);
_avatarBillboardTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS);
@ -162,20 +139,14 @@ void ScriptEngine::setIsAvatar(bool isAvatar) {
void ScriptEngine::setAvatarData(AvatarData* avatarData, const QString& objectName) {
_avatarData = avatarData;
// remove the old Avatar property, if it exists
_engine.globalObject().setProperty(objectName, QScriptValue());
// give the script engine the new Avatar script property
registerGlobalObject(objectName, _avatarData);
}
void ScriptEngine::cleanupMenuItems() {
if (_wantMenuItems) {
emit cleanupMenuItem(_scriptMenuName);
}
}
bool ScriptEngine::setScriptContents(const QString& scriptContents, const QString& fileNameString) {
if (_isRunning) {
return false;
@ -203,7 +174,7 @@ void ScriptEngine::init() {
registerVoxelMetaTypes(&_engine);
registerEventTypes(&_engine);
registerMenuItemProperties(&_engine);
qScriptRegisterMetaType(&_engine, ParticlePropertiesToScriptValue, ParticlePropertiesFromScriptValue);
qScriptRegisterMetaType(&_engine, ParticleIDtoScriptValue, ParticleIDfromScriptValue);
qScriptRegisterSequenceMetaType<QVector<ParticleID> >(&_engine);
@ -216,7 +187,7 @@ void ScriptEngine::init() {
QScriptValue injectionOptionValue = _engine.scriptValueFromQMetaObject<AudioInjectorOptions>();
_engine.globalObject().setProperty("AudioInjectionOptions", injectionOptionValue);
QScriptValue localVoxelsValue = _engine.scriptValueFromQMetaObject<LocalVoxels>();
_engine.globalObject().setProperty("LocalVoxels", localVoxelsValue);
@ -285,9 +256,9 @@ void ScriptEngine::run() {
gettimeofday(&startTime, NULL);
int thisFrame = 0;
NodeList* nodeList = NodeList::getInstance();
qint64 lastUpdate = usecTimestampNow();
while (!_isFinished) {
@ -325,36 +296,36 @@ void ScriptEngine::run() {
_particlesScriptingInterface.getParticlePacketSender()->process();
}
}
if (_isAvatar && _avatarData) {
const int SCRIPT_AUDIO_BUFFER_SAMPLES = floor(((SCRIPT_DATA_CALLBACK_USECS * SAMPLE_RATE) / (1000 * 1000)) + 0.5);
const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t);
QByteArray avatarPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarData);
avatarPacket.append(_avatarData->toByteArray());
nodeList->broadcastToNodes(avatarPacket, NodeSet() << NodeType::AvatarMixer);
if (_isListeningToAudioStream || _avatarSound) {
// if we have an avatar audio stream then send it out to our audio-mixer
bool silentFrame = true;
int16_t numAvailableSamples = SCRIPT_AUDIO_BUFFER_SAMPLES;
const int16_t* nextSoundOutput = NULL;
if (_avatarSound) {
const QByteArray& soundByteArray = _avatarSound->getByteArray();
nextSoundOutput = reinterpret_cast<const int16_t*>(soundByteArray.data()
+ _numAvatarSoundSentBytes);
int numAvailableBytes = (soundByteArray.size() - _numAvatarSoundSentBytes) > SCRIPT_AUDIO_BUFFER_BYTES
? SCRIPT_AUDIO_BUFFER_BYTES
: soundByteArray.size() - _numAvatarSoundSentBytes;
numAvailableSamples = numAvailableBytes / sizeof(int16_t);
// check if the all of the _numAvatarAudioBufferSamples to be sent are silence
for (int i = 0; i < numAvailableSamples; ++i) {
if (nextSoundOutput[i] != 0) {
@ -362,7 +333,7 @@ void ScriptEngine::run() {
break;
}
}
_numAvatarSoundSentBytes += numAvailableBytes;
if (_numAvatarSoundSentBytes == soundByteArray.size()) {
// we're done with this sound object - so set our pointer back to NULL
@ -371,24 +342,24 @@ void ScriptEngine::run() {
_numAvatarSoundSentBytes = 0;
}
}
QByteArray audioPacket = byteArrayWithPopulatedHeader(silentFrame
? PacketTypeSilentAudioFrame
: PacketTypeMicrophoneAudioNoEcho);
QDataStream packetStream(&audioPacket, QIODevice::Append);
// use the orientation and position of this avatar for the source of this audio
packetStream.writeRawData(reinterpret_cast<const char*>(&_avatarData->getPosition()), sizeof(glm::vec3));
glm::quat headOrientation = _avatarData->getHeadOrientation();
packetStream.writeRawData(reinterpret_cast<const char*>(&headOrientation), sizeof(glm::quat));
if (silentFrame) {
if (!_isListeningToAudioStream) {
// if we have a silent frame and we're not listening then just send nothing and break out of here
break;
}
// write the number of silent samples so the audio-mixer can uphold timing
packetStream.writeRawData(reinterpret_cast<const char*>(&SCRIPT_AUDIO_BUFFER_SAMPLES), sizeof(int16_t));
} else if (nextSoundOutput) {
@ -396,7 +367,7 @@ void ScriptEngine::run() {
packetStream.writeRawData(reinterpret_cast<const char*>(nextSoundOutput),
numAvailableSamples * sizeof(int16_t));
}
nodeList->broadcastToNodes(audioPacket, NodeSet() << NodeType::AudioMixer);
}
}
@ -412,10 +383,10 @@ void ScriptEngine::run() {
}
}
emit scriptEnding();
// kill the avatar identity timer
delete _avatarIdentityTimer;
if (_voxelsScriptingInterface.getVoxelPacketSender()->serversExist()) {
// release the queue of edit voxel messages.
_voxelsScriptingInterface.getVoxelPacketSender()->releaseQueuedMessages();
@ -435,8 +406,6 @@ void ScriptEngine::run() {
_particlesScriptingInterface.getParticlePacketSender()->process();
}
}
cleanupMenuItems();
// If we were on a thread, then wait till it's done
if (thread()) {
@ -444,7 +413,7 @@ void ScriptEngine::run() {
}
emit finished(_fileNameString);
_isRunning = false;
}
@ -454,13 +423,13 @@ void ScriptEngine::stop() {
void ScriptEngine::timerFired() {
QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());
// call the associated JS function, if it exists
QScriptValue timerFunction = _timerFunctionMap.value(callingTimer);
if (timerFunction.isValid()) {
timerFunction.call();
}
if (!callingTimer->isActive()) {
// this timer is done, we can kill it
delete callingTimer;
@ -471,14 +440,14 @@ QObject* ScriptEngine::setupTimerWithInterval(const QScriptValue& function, int
// create the timer, add it to the map, and start it
QTimer* newTimer = new QTimer(this);
newTimer->setSingleShot(isSingleShot);
connect(newTimer, &QTimer::timeout, this, &ScriptEngine::timerFired);
// make sure the timer stops when the script does
connect(this, &ScriptEngine::scriptEnding, newTimer, &QTimer::stop);
_timerFunctionMap.insert(newTimer, function);
newTimer->start(intervalMS);
return newTimer;
}
@ -505,17 +474,17 @@ QUrl ScriptEngine::resolveInclude(const QString& include) const {
if (!url.scheme().isEmpty()) {
return url;
}
// we apparently weren't a fully qualified url, so, let's assume we're relative
// we apparently weren't a fully qualified url, so, let's assume we're relative
// to the original URL of our script
QUrl parentURL(_fileNameString);
// if the parent URL's scheme is empty, then this is probably a local file...
if (parentURL.scheme().isEmpty()) {
parentURL = QUrl::fromLocalFile(_fileNameString);
}
// at this point we should have a legitimate fully qualified URL for our parent
// at this point we should have a legitimate fully qualified URL for our parent
url = parentURL.resolved(url);
return url;
}
@ -543,7 +512,7 @@ void ScriptEngine::include(const QString& includeFile) {
loop.exec();
includeContents = reply->readAll();
}
QScriptValue result = _engine.evaluate(includeContents);
if (_engine.hasUncaughtException()) {
int line = _engine.uncaughtExceptionLineNumber();

View file

@ -33,11 +33,11 @@ const unsigned int SCRIPT_DATA_CALLBACK_USECS = floor(((1.0 / 60.0f) * 1000 * 10
class ScriptEngine : public QObject {
Q_OBJECT
public:
ScriptEngine(const QUrl& scriptURL, bool wantMenuItems = false,
ScriptEngine(const QUrl& scriptURL,
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
ScriptEngine(const QString& scriptContents = NO_SCRIPT, bool wantMenuItems = false,
const QString& fileNameString = QString(""),
ScriptEngine(const QString& scriptContents = NO_SCRIPT,
const QString& fileNameString = QString(""),
AbstractControllerScriptingInterface* controllerScriptingInterface = NULL);
/// Access the VoxelsScriptingInterface in order to initialize it with a custom packet sender and jurisdiction listener
@ -49,39 +49,39 @@ public:
/// sets the script contents, will return false if failed, will fail if script is already running
bool setScriptContents(const QString& scriptContents, const QString& fileNameString = QString(""));
const QString& getScriptMenuName() const { return _scriptMenuName; }
const QString& getScriptName() const { return _scriptName; }
void cleanupMenuItems();
void registerGlobalObject(const QString& name, QObject* object); /// registers a global object by name
Q_INVOKABLE void setIsAvatar(bool isAvatar);
bool isAvatar() const { return _isAvatar; }
void setAvatarData(AvatarData* avatarData, const QString& objectName);
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; }
void setAvatarSound(Sound* avatarSound) { _avatarSound = avatarSound; }
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
void init();
void run(); /// runs continuously until Agent.stop() is called
void evaluate(); /// initializes the engine, and evaluates the script, but then returns control to caller
void timerFired();
bool hasScript() const { return !_scriptContents.isEmpty(); }
public slots:
void stop();
QObject* setInterval(const QScriptValue& function, int intervalMS);
QObject* setTimeout(const QScriptValue& function, int timeoutMS);
void clearInterval(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
void clearTimeout(QObject* timer) { stopTimer(reinterpret_cast<QTimer*>(timer)); }
void include(const QString& includeFile);
signals:
void update(float deltaTime);
void scriptEnding();
@ -106,19 +106,18 @@ private:
QUrl resolveInclude(const QString& include) const;
void sendAvatarIdentityPacket();
void sendAvatarBillboardPacket();
QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot);
void stopTimer(QTimer* timer);
static VoxelsScriptingInterface _voxelsScriptingInterface;
static ParticlesScriptingInterface _particlesScriptingInterface;
static int _scriptNumber;
AbstractControllerScriptingInterface* _controllerScriptingInterface;
AudioScriptingInterface _audioScriptingInterface;
AvatarData* _avatarData;
bool _wantMenuItems;
QString _scriptMenuName;
QString _scriptName;
QString _fileNameString;
Quat _quatLibrary;
Vec3 _vec3Library;