mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-05-06 19:39:56 -05:00
Merge branch 'timeadjustments' of openspace.itn.liu.se:/openspace into timeadjustments
This commit is contained in:
+1
-2
@@ -145,8 +145,7 @@ endif ()
|
||||
#########################################################################################
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
#add_subdirectory(gui)
|
||||
add_subdirectory(gui)
|
||||
|
||||
#########################################################################################
|
||||
# File Fetch
|
||||
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
add_subdirectory(luascriptexternalcontrol)
|
||||
add_subdirectory(luascriptexternalcontrol)
|
||||
add_subdirectory(timelineview)
|
||||
@@ -0,0 +1,10 @@
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
|
||||
project(TimelineView)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
find_package(Qt5Widgets)
|
||||
find_package(Qt5Network)
|
||||
add_executable(TimelineView main.cpp mainwindow.cpp configurationwidget.cpp informationwidget.cpp timecontrolwidget.cpp timelinewidget.cpp)
|
||||
target_link_libraries(TimelineView Qt5::Widgets Qt5::Network)
|
||||
@@ -0,0 +1,52 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "configurationwidget.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
|
||||
ConfigurationWidget::ConfigurationWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, _ipAddress(new QLineEdit("localhost"))
|
||||
, _port(new QLineEdit("20500"))
|
||||
, _connect(new QPushButton("Connect"))
|
||||
, _playbook(new QLineEdit)
|
||||
, _load(new QPushButton("Load"))
|
||||
{
|
||||
QGridLayout* layout = new QGridLayout;
|
||||
layout->addWidget(_ipAddress, 0, 0);
|
||||
layout->addWidget(_port, 0, 1);
|
||||
layout->addWidget(_connect, 0, 2);
|
||||
layout->addWidget(_playbook, 1, 0, 1, 2);
|
||||
layout->addWidget(_load, 1, 2);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
QObject::connect(_connect, SIGNAL(clicked()), this, SLOT(onConnectButton()));
|
||||
|
||||
}
|
||||
|
||||
void ConfigurationWidget::onConnectButton() {
|
||||
emit connect(_ipAddress->text(), _port->text());
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __CONFIGURATIONWIDGET_H__
|
||||
#define __CONFIGURATIONWIDGET_H__
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
|
||||
class ConfigurationWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConfigurationWidget(QWidget* parent);
|
||||
|
||||
signals:
|
||||
void connect(QString host, QString port);
|
||||
|
||||
private slots:
|
||||
void onConnectButton();
|
||||
|
||||
private:
|
||||
QLineEdit* _ipAddress;
|
||||
QLineEdit* _port;
|
||||
QPushButton* _connect;
|
||||
|
||||
QLineEdit* _playbook;
|
||||
QPushButton* _load;
|
||||
};
|
||||
|
||||
#endif // __CONFIGURATIONWIDGET_H__
|
||||
@@ -0,0 +1,33 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "informationwidget.h"
|
||||
|
||||
#include <QLayout>
|
||||
#include <QTextEdit>
|
||||
|
||||
InformationWidget::InformationWidget(QWidget* parent)
|
||||
: QTextEdit(parent)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __INFORMATIONWIDGET_H__
|
||||
#define __INFORMATIONWIDGET_H__
|
||||
|
||||
#include <QTextEdit>
|
||||
|
||||
class InformationWidget : public QTextEdit {
|
||||
Q_OBJECT
|
||||
public:
|
||||
InformationWidget(QWidget* parent);
|
||||
};
|
||||
|
||||
#endif // __INFORMATIONWIDGET_H__
|
||||
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <QApplication>
|
||||
#include "mainwindow.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include "configurationwidget.h"
|
||||
#include "timecontrolwidget.h"
|
||||
#include "informationwidget.h"
|
||||
#include "timelinewidget.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
MainWindow::MainWindow()
|
||||
: QWidget(nullptr)
|
||||
, _configurationWidget(nullptr)
|
||||
, _timeControlWidget(nullptr)
|
||||
, _informationWidget(nullptr)
|
||||
, _timelineWidget(nullptr)
|
||||
, _socket(nullptr)
|
||||
{
|
||||
setWindowTitle("OpenSpace Timeline");
|
||||
|
||||
_configurationWidget = new ConfigurationWidget(this);
|
||||
_timeControlWidget = new TimeControlWidget(this);
|
||||
_informationWidget = new InformationWidget(this);
|
||||
_timelineWidget = new TimelineWidget(this);
|
||||
|
||||
QGridLayout* layout = new QGridLayout;
|
||||
layout->addWidget(_configurationWidget, 0, 0);
|
||||
layout->addWidget(_timeControlWidget, 1, 0);
|
||||
layout->addWidget(_informationWidget, 2, 0);
|
||||
layout->addWidget(_timelineWidget, 0, 1, 3, 1);
|
||||
|
||||
|
||||
QObject::connect(
|
||||
_configurationWidget, SIGNAL(connect(QString, QString)),
|
||||
this, SLOT(onConnect(QString, QString))
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
_timeControlWidget, SIGNAL(scriptActivity(QString)),
|
||||
this, SLOT(sendScript(QString))
|
||||
);
|
||||
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete _socket;
|
||||
}
|
||||
|
||||
void MainWindow::onConnect(QString host, QString port) {
|
||||
delete _socket;
|
||||
|
||||
_socket = new QTcpSocket(this);
|
||||
connect(_socket, SIGNAL(readyRead()), SLOT(readTcpData()));
|
||||
_socket->connectToHost(host, port.toUInt());
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::readTcpData() {
|
||||
static const uint8_t MessageTypeStatus = 0;
|
||||
|
||||
QByteArray data = _socket->readAll();
|
||||
|
||||
if (QString(data) == "Connected to SGCT!\r\n")
|
||||
return;
|
||||
if (QString(data) == "OK\r\n")
|
||||
return;
|
||||
|
||||
uint8_t messageType = data[0];
|
||||
|
||||
if (messageType == MessageTypeStatus)
|
||||
handleStatusMessage(data.mid(1));
|
||||
handleStatusMessage(data.right(data.length() - 1));
|
||||
}
|
||||
|
||||
void MainWindow::handleStatusMessage(QByteArray data) {
|
||||
const char* buffer = data.data();
|
||||
|
||||
union {
|
||||
double value;
|
||||
std::array<char, 8> buffer;
|
||||
} et;
|
||||
std::memmove(et.buffer.data(), buffer, sizeof(double));
|
||||
|
||||
std::vector<char> timeString(24);
|
||||
std::memmove(timeString.data(), buffer + sizeof(double), 24);
|
||||
|
||||
union {
|
||||
double value;
|
||||
std::array<char, 8> buffer;
|
||||
} delta;
|
||||
std::memmove(delta.buffer.data(), buffer + sizeof(double) + 24, sizeof(double));
|
||||
|
||||
_timeControlWidget->update(
|
||||
QString::fromStdString(std::string(timeString.begin(), timeString.end())),
|
||||
QString::number(delta.value)
|
||||
);
|
||||
}
|
||||
|
||||
void MainWindow::sendScript(QString script) {
|
||||
_socket->write(("0" + script + "\r\n").toLatin1());
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __MAINWINDOW_H__
|
||||
#define __MAINWINDOW_H__
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTcpSocket>
|
||||
|
||||
class ConfigurationWidget;
|
||||
class TimeControlWidget;
|
||||
class InformationWidget;
|
||||
class TimelineWidget;
|
||||
|
||||
class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow();
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void sendScript(QString script);
|
||||
|
||||
private slots:
|
||||
void onConnect(QString host, QString port);
|
||||
|
||||
//void onConnectButton();
|
||||
//void sendCommandButton();
|
||||
void readTcpData();
|
||||
void handleStatusMessage(QByteArray data);
|
||||
|
||||
private:
|
||||
ConfigurationWidget* _configurationWidget;
|
||||
TimeControlWidget* _timeControlWidget;
|
||||
InformationWidget* _informationWidget;
|
||||
TimelineWidget* _timelineWidget;
|
||||
|
||||
QTcpSocket* _socket;
|
||||
};
|
||||
|
||||
#endif // __MAINWINDOW_H__
|
||||
@@ -0,0 +1,131 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "timecontrolwidget.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QSlider>
|
||||
|
||||
TimeControlWidget::TimeControlWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, _currentTime(new QLabel("Current Time"))
|
||||
, _setTime(new QComboBox)
|
||||
, _currentDelta(new QLabel("Current Delta"))
|
||||
, _setDelta(new QSlider(Qt::Horizontal))
|
||||
, _rewind(new QPushButton("<<"))
|
||||
, _pause(new QPushButton("||"))
|
||||
, _play(new QPushButton("|>"))
|
||||
, _forward(new QPushButton(">>"))
|
||||
{
|
||||
_setDelta->setMinimum(-100);
|
||||
_setDelta->setMaximum(100);
|
||||
_setDelta->setValue(0);
|
||||
QObject::connect(
|
||||
_setDelta,
|
||||
SIGNAL(valueChanged(int)),
|
||||
this,
|
||||
SLOT(onValueChange())
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
_rewind,
|
||||
SIGNAL(clicked()),
|
||||
this,
|
||||
SLOT(onRewindButton())
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
_pause,
|
||||
SIGNAL(clicked()),
|
||||
this,
|
||||
SLOT(onPauseButton())
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
_play,
|
||||
SIGNAL(clicked()),
|
||||
this,
|
||||
SLOT(onPlayButton())
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
_forward,
|
||||
SIGNAL(clicked()),
|
||||
this,
|
||||
SLOT(onForwardButton())
|
||||
);
|
||||
|
||||
QGridLayout* layout = new QGridLayout;
|
||||
|
||||
layout->addWidget(_currentTime, 0, 0);
|
||||
layout->addWidget(_setTime, 0, 1);
|
||||
layout->addWidget(_currentDelta, 1, 0);
|
||||
layout->addWidget(_setDelta, 2, 0, 1, 2);
|
||||
|
||||
QWidget* controlContainer = new QWidget;
|
||||
QHBoxLayout* controlContainerLayout = new QHBoxLayout;
|
||||
controlContainerLayout->addWidget(_rewind);
|
||||
controlContainerLayout->addWidget(_pause);
|
||||
controlContainerLayout->addWidget(_play);
|
||||
controlContainerLayout->addWidget(_forward);
|
||||
controlContainer->setLayout(controlContainerLayout);
|
||||
layout->addWidget(controlContainer, 3, 0, 1, 2);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void TimeControlWidget::update(QString currentTime, QString currentDelta) {
|
||||
_currentTime->setText(currentTime);
|
||||
_currentDelta->setText(currentDelta);
|
||||
}
|
||||
|
||||
void TimeControlWidget::onValueChange() {
|
||||
QString script = "openspace.time.setDeltaTime(" + QString::number(_setDelta->value()) + ");";
|
||||
emit scriptActivity(script);
|
||||
}
|
||||
|
||||
void TimeControlWidget::onRewindButton() {
|
||||
QString script = "openspace.time.setDeltaTime(-openspace.time.deltaTime());";
|
||||
emit scriptActivity(script);
|
||||
}
|
||||
|
||||
void TimeControlWidget::onPauseButton() {
|
||||
QString script = "openspace.time.setPause(true);";
|
||||
emit scriptActivity(script);
|
||||
}
|
||||
|
||||
void TimeControlWidget::onPlayButton() {
|
||||
QString script = "openspace.time.setPause(false);";
|
||||
emit scriptActivity(script);
|
||||
}
|
||||
|
||||
void TimeControlWidget::onForwardButton() {
|
||||
QString script = "openspace.time.setDeltaTime(-openspace.time.deltaTime());";
|
||||
emit scriptActivity(script);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __TIMECONTROLWIDGET_H__
|
||||
#define __TIMECONTROLWIDGET_H__
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
class QSlider;
|
||||
|
||||
class TimeControlWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimeControlWidget(QWidget* parent);
|
||||
|
||||
void update(QString currentTime, QString currentDelta);
|
||||
|
||||
signals:
|
||||
void scriptActivity(QString script);
|
||||
|
||||
private slots:
|
||||
void onValueChange();
|
||||
void onRewindButton();
|
||||
void onPauseButton();
|
||||
void onPlayButton();
|
||||
void onForwardButton();
|
||||
|
||||
private:
|
||||
QLabel* _currentTime;
|
||||
QComboBox* _setTime;
|
||||
QLabel* _currentDelta;
|
||||
QSlider* _setDelta;
|
||||
QPushButton* _rewind;
|
||||
QPushButton* _pause;
|
||||
QPushButton* _play;
|
||||
QPushButton* _forward;
|
||||
|
||||
bool _stateNoNotification = false;
|
||||
};
|
||||
|
||||
#endif // __TIMECONTROLWIDGET_H__
|
||||
@@ -0,0 +1,42 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "timelinewidget.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
|
||||
TimelineWidget::TimelineWidget(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setMinimumWidth(300);
|
||||
setMinimumHeight(500);
|
||||
}
|
||||
|
||||
void TimelineWidget::paintEvent(QPaintEvent* event) {
|
||||
QPainter painter(this);
|
||||
|
||||
painter.setBrush(QBrush(Qt::white));
|
||||
painter.drawRect(contentsRect());
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __TIMELINEWIDGET_H__
|
||||
#define __TIMELINEWIDGET_H__
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QPaintEvent;
|
||||
|
||||
class TimelineWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
TimelineWidget(QWidget* parent);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
||||
};
|
||||
|
||||
#endif // __TIMELINEWIDGET_H__
|
||||
@@ -40,6 +40,7 @@ namespace openspace {
|
||||
|
||||
class ConfigurationManager;
|
||||
class LuaConsole;
|
||||
class NetworkEngine;
|
||||
class GUI;
|
||||
class RenderEngine;
|
||||
class SyncBuffer;
|
||||
@@ -111,6 +112,7 @@ private:
|
||||
interaction::InteractionHandler* _interactionHandler;
|
||||
RenderEngine* _renderEngine;
|
||||
scripting::ScriptEngine* _scriptEngine;
|
||||
NetworkEngine* _networkEngine;
|
||||
ghoul::cmdparser::CommandlineParser* _commandlineParser;
|
||||
LuaConsole* _console;
|
||||
gui::GUI* _gui;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __NETWORKENGINE_H__
|
||||
#define __NETWORKENGINE_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class NetworkEngine {
|
||||
public:
|
||||
NetworkEngine() = default;
|
||||
|
||||
bool handleMessage(const std::string& message);
|
||||
|
||||
void sendStatusMessage();
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __NETWORKENGINE_H__
|
||||
@@ -51,7 +51,7 @@ namespace openspace {
|
||||
* equal to the frame time.
|
||||
*/
|
||||
|
||||
class SyncBuffer;
|
||||
class SyncBuffer;
|
||||
|
||||
class Time {
|
||||
public:
|
||||
|
||||
@@ -48,6 +48,12 @@ file(GLOB ENGINE_HEADER ${HEADER_ROOT_DIR}/openspace/engine/*.h)
|
||||
set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${ENGINE_HEADER})
|
||||
source_group(Engine FILES ${ENGINE_SOURCE} ${ENGINE_HEADER})
|
||||
|
||||
file(GLOB NETWORK_SOURCE ${SOURCE_ROOT_DIR}/network/*.cpp)
|
||||
set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${NETWORK_SOURCE})
|
||||
file(GLOB NETWORK_HEADER ${HEADER_ROOT_DIR}/openspace/network/*.h)
|
||||
set(OPENSPACE_HEADER ${OPENSPACE_HEADER} ${NETWORK_HEADER})
|
||||
source_group(Network FILES ${NETWORK_SOURCE} ${NETWORK_HEADER})
|
||||
|
||||
file(GLOB GUI_SOURCE ${SOURCE_ROOT_DIR}/gui/*.cpp)
|
||||
set(OPENSPACE_SOURCE ${OPENSPACE_SOURCE} ${GUI_SOURCE})
|
||||
file(GLOB GUI_HEADER ${HEADER_ROOT_DIR}/openspace/gui/*.h)
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <openspace/interaction/keyboardcontroller.h>
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
#include <openspace/interaction/mousecontroller.h>
|
||||
#include <openspace/network/networkengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/scenegraph/scenegraph.h>
|
||||
@@ -93,6 +94,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName)
|
||||
, _interactionHandler(new interaction::InteractionHandler)
|
||||
, _renderEngine(new RenderEngine)
|
||||
, _scriptEngine(new scripting::ScriptEngine)
|
||||
, _networkEngine(new NetworkEngine)
|
||||
, _commandlineParser(new ghoul::cmdparser::CommandlineParser(programName, true))
|
||||
, _console(new LuaConsole)
|
||||
, _gui(new gui::GUI)
|
||||
@@ -113,6 +115,7 @@ OpenSpaceEngine::~OpenSpaceEngine() {
|
||||
delete _interactionHandler;
|
||||
delete _renderEngine;
|
||||
delete _scriptEngine;
|
||||
delete _networkEngine;
|
||||
delete _commandlineParser;
|
||||
delete _console;
|
||||
delete _gui;
|
||||
@@ -698,6 +701,7 @@ void OpenSpaceEngine::encode() {
|
||||
|
||||
_syncBuffer->write();
|
||||
}
|
||||
_networkEngine->sendStatusMessage();
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::decode() {
|
||||
@@ -707,7 +711,6 @@ void OpenSpaceEngine::decode() {
|
||||
Time::ref().deserialize(_syncBuffer);
|
||||
_scriptEngine->deserialize(_syncBuffer);
|
||||
_renderEngine->deserialize(_syncBuffer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -717,17 +720,7 @@ void OpenSpaceEngine::externalControlCallback(const char* receivedChars,
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
// The first byte determines the type of message
|
||||
const char type = receivedChars[0];
|
||||
switch (type) {
|
||||
case '0': // LuaScript
|
||||
{
|
||||
std::string script = std::string(receivedChars + 1);
|
||||
LINFO("Received Lua Script: '" << script << "'");
|
||||
//_scriptEngine->runScript(script);
|
||||
_scriptEngine->queueScript(script);
|
||||
}
|
||||
}
|
||||
_networkEngine->handleMessage(std::string(receivedChars));
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::enableBarrier() {
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2015 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/network/networkengine.h>
|
||||
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
|
||||
#include "sgct.h"
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "NetworkEngine";
|
||||
|
||||
const uint8_t MessageTypeStatus = 0;
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
bool NetworkEngine::handleMessage(const std::string& message) {
|
||||
// The first byte determines the type of message
|
||||
const char type = message[0];
|
||||
switch (type) {
|
||||
case '0': // LuaScript
|
||||
{
|
||||
std::string script = message.substr(1);
|
||||
//LINFO("Received Lua Script: '" << script << "'");
|
||||
OsEng.scriptEngine()->queueScript(script);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LERROR("Unknown type '" << type << "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void NetworkEngine::sendStatusMessage() {
|
||||
if (!sgct::Engine::instance()->isExternalControlConnected())
|
||||
return;
|
||||
// Protocols:
|
||||
// 1 byte: type of message
|
||||
// 8 bytes: time as a ET double
|
||||
// 24 bytes: time as a UTC string
|
||||
// 8 bytes: delta time as double
|
||||
// Total: 41
|
||||
|
||||
uint16_t messageSize = 0;
|
||||
|
||||
double time = Time::ref().currentTime();
|
||||
std::string timeString = Time::ref().currentTimeUTC();
|
||||
double delta = Time::ref().deltaTime();
|
||||
|
||||
messageSize += sizeof(uint8_t);
|
||||
messageSize += sizeof(time);
|
||||
messageSize += timeString.length();
|
||||
messageSize += sizeof(delta);
|
||||
|
||||
//LINFO(delta);
|
||||
|
||||
ghoul_assert(messageSize == 41, "Message size is not correct");
|
||||
|
||||
unsigned int currentLocation = 0;
|
||||
std::vector<char> buffer(messageSize);
|
||||
|
||||
std::memcpy(buffer.data(), &MessageTypeStatus, sizeof(MessageTypeStatus));
|
||||
currentLocation += sizeof(MessageTypeStatus);
|
||||
std::memmove(buffer.data() + currentLocation, &time, sizeof(time));
|
||||
currentLocation += sizeof(time);
|
||||
std::memmove(buffer.data() + currentLocation, timeString.c_str(), timeString.length());
|
||||
currentLocation += timeString.length();
|
||||
std::memmove(buffer.data() + currentLocation, &delta, sizeof(delta));
|
||||
|
||||
sgct::Engine::instance()->sendMessageToExternalControl(buffer.data(), messageSize);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -46,7 +46,7 @@ namespace openspace {
|
||||
std::string spacecraft,
|
||||
ghoul::Dictionary translationDictionary,
|
||||
std::vector<std::string> potentialTargets) :
|
||||
_defaultCaptureImage(absPath("C:/Users/michal/openspace/openspace-data/scene/common/textures/placeholder_blank.png"))
|
||||
_defaultCaptureImage(absPath("${OPENSPACE_DATA}/scene/common/textures/placeholder_blank.png"))
|
||||
{
|
||||
_fileName = fileName;
|
||||
_spacecraft = spacecraft;
|
||||
|
||||
@@ -78,7 +78,7 @@ ImageSequencer::ImageSequencer()
|
||||
, _currentTime(-1.0)
|
||||
, _sequenceIDs(0)
|
||||
, _targetsAdded(false)
|
||||
, _defaultCaptureImage(absPath("C:/Users/michal/openspace/openspace-data/scene/common/textures/placeholder_blank.png"))
|
||||
, _defaultCaptureImage(absPath("${OPENSPACE_DATA}/scene/common/textures/placeholder_blank.png"))
|
||||
{}
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ ImageSequencer2* ImageSequencer2::_instance = nullptr;
|
||||
|
||||
ImageSequencer2::ImageSequencer2() :
|
||||
_hasData(false),
|
||||
_defaultCaptureImage(absPath("C:/Users/michal/openspace/openspace-data/scene/common/textures/placeholder_blank.png"))
|
||||
_defaultCaptureImage(absPath("${OPENSPACE_DATA}/scene/common/textures/placeholder_blank.png"))
|
||||
{}
|
||||
|
||||
ImageSequencer2& ImageSequencer2::ref() {
|
||||
|
||||
Reference in New Issue
Block a user