Commit 540783ad authored by schultezub's avatar schultezub
Browse files

* Started implementing a GUI: introducing MainWindow, PipelineTreeWidget

 * elaborated checks in TumVisApplication
 * added AbstractPipeline.getName() and AbstractProcessor.getName()

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@204 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent c32b41e0
......@@ -6,10 +6,12 @@ MESSAGE(STATUS "Configuring TUMVis Application")
FILE(GLOB TUMVIS_APPLICATION_SOURCES
*.cpp
gui/*.cpp
)
FILE(GLOB TUMVIS_APPLICATION_HEADERS
*.h
gui/*.h
)
#SET(TUMVIS_APPLICATION_SOURCES
......@@ -19,7 +21,8 @@ FILE(GLOB TUMVIS_APPLICATION_HEADERS
#)
SET(TUMVIS_APPLICATION_TO_BE_MOCCED
tumvisapplication.h
gui/mainwindow.h
gui/pipelinetreewidget.h
)
#
......
#include "mainwindow.h"
#include "tgt/assert.h"
#include "application/tumvisapplication.h"
namespace TUMVis {
MainWindow::MainWindow(TumVisApplication* application)
: QMainWindow()
, _application(application)
, _pipelineWidget(0)
{
tgtAssert(_application != 0, "Application must not be 0.");
setup();
}
MainWindow::~MainWindow() {
}
void MainWindow::setup() {
_pipelineWidget = new PipelineTreeWidget(this);
setCentralWidget(_pipelineWidget);
connect(this, SIGNAL(updatePipelineWidget(const std::vector<AbstractPipeline*>&)), _pipelineWidget, SLOT(update(const std::vector<AbstractPipeline*>&)));
_application->s_PipelinesChanged.connect(this, &MainWindow::onPipelinesChanged);
}
void MainWindow::onPipelinesChanged() {
emit updatePipelineWidget(_application->_pipelines);
}
}
\ No newline at end of file
#ifndef TUMVISMAINWINDOW_H__
#define TUMVISMAINWINDOW_H__
#include "sigslot/sigslot.h"
#include "application/tumvisapplication.h"
#include "application/gui/pipelinetreewidget.h"
#include <QMainWindow>
#include <vector>
namespace TUMVis {
class MainWindow : public QMainWindow, public sigslot::has_slots<> {
Q_OBJECT;
public:
MainWindow(TumVisApplication* application);
~MainWindow();
void onPipelinesChanged();
signals:
void updatePipelineWidget(const std::vector<AbstractPipeline*>&);
private:
void setup();
TumVisApplication* _application; ///< Pointer to the application hosting the whole stuff
PipelineTreeWidget* _pipelineWidget; ///< Widget for browsing the active pipelines
};
}
#endif // TUMVISMAINWINDOW_H__
#include "pipelinetreewidget.h"
#include "tgt/assert.h"
#include <QHeaderView>
#include <QStringList>
namespace TUMVis {
// = TreeModel items ==============================================================================
TreeItem::TreeItem(TreeItem* parent /*= 0*/)
: _parent(parent)
{
if (_parent != 0)
_parent->_children.append(this);
}
TreeItem::~TreeItem() {
qDeleteAll(_children);
}
TreeItem* TreeItem::getParent() {
return _parent;
}
TreeItem* TreeItem::getChild(int row) {
return _children.value(row);
}
int TreeItem::getRow() {
if (_parent)
return _parent->_children.indexOf(const_cast<TreeItem*>(this));
return 0;
}
int TreeItem::getChildCount() {
return _children.count();
}
PipelineTreeItem::PipelineTreeItem(AbstractPipeline* pipeline, TreeItem* parent)
: TreeItem(parent)
, _pipeline(pipeline)
{
tgtAssert(_pipeline != 0, "Pipeline must not be 0.");
}
QVariant PipelineTreeItem::getData(int column) const {
if (column == 0)
return QVariant(QString::fromStdString(_pipeline->getName()));
return QVariant();
}
PipelineTreeItem::~PipelineTreeItem() {
}
ProcessorTreeItem::ProcessorTreeItem(AbstractProcessor* processor, TreeItem* parent)
: TreeItem(parent)
, _processor(processor)
{
tgtAssert(_processor != 0, "Processor must not be 0.");
}
QVariant ProcessorTreeItem::getData(int column) const {
if (column == 0)
return QVariant(QString::fromStdString(_processor->getName()));
return QVariant();
}
ProcessorTreeItem::~ProcessorTreeItem() {
}
RootTreeItem::RootTreeItem(TreeItem* parent /*= 0*/)
: TreeItem(parent)
{}
QVariant RootTreeItem::getData(int column) const {
if (column == 0)
return QVariant(QString("Pipeline/Processor"));
else if (column == 1)
return QVariant(QString("Description"));
return QVariant();
}
RootTreeItem::~RootTreeItem() {
}
// = PipelineTreeModel ============================================================================
PipelineTreeModel::PipelineTreeModel(QObject *parent /*= 0*/)
: QAbstractItemModel(parent)
, _rootItem(new RootTreeItem(0))
{
}
PipelineTreeModel::~PipelineTreeModel() {
delete _rootItem;
}
QVariant PipelineTreeModel::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
return item->getData(index.column());
}
Qt::ItemFlags PipelineTreeModel::flags(const QModelIndex &index) const {
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant PipelineTreeModel::headerData(int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return _rootItem->getData(section);
return QVariant();
}
QModelIndex PipelineTreeModel::index(int row, int column, const QModelIndex &parent /*= QModelIndex()*/) const {
if (!hasIndex(row, column, parent))
return QModelIndex();
TreeItem* parentItem;
if (!parent.isValid())
parentItem = _rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
TreeItem* childItem = parentItem->getChild(row);
if (childItem)
return createIndex(row, column, childItem);
else
return QModelIndex();
}
QModelIndex PipelineTreeModel::parent(const QModelIndex &index) const {
if (!index.isValid())
return QModelIndex();
TreeItem* childItem = static_cast<TreeItem*>(index.internalPointer());
TreeItem* parentItem = childItem->getParent();
if (parentItem == _rootItem)
return QModelIndex();
return createIndex(parentItem->getRow(), 0, parentItem);
}
int PipelineTreeModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const {
TreeItem* parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = _rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->getChildCount();
}
int PipelineTreeModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const {
return 2;
}
void PipelineTreeModel::setData(const std::vector<AbstractPipeline*>& pipelines) {
for (std::vector<AbstractPipeline*>::const_iterator pipe = pipelines.begin(); pipe != pipelines.end(); ++pipe) {
PipelineTreeItem* pipeti = new PipelineTreeItem(*pipe, _rootItem);
for (std::vector<AbstractProcessor*>::const_iterator proc = (*pipe)->getProcessors().begin(); proc != (*pipe)->getProcessors().end(); ++proc) {
ProcessorTreeItem* procti = new ProcessorTreeItem(*proc, pipeti);
}
}
}
// = PipelineTreeWidget ===========================================================================
PipelineTreeWidget::PipelineTreeWidget(QWidget* parent /*= 0*/)
: QTreeView(parent)
{
setupWidget();
}
PipelineTreeWidget::~PipelineTreeWidget() {
}
void PipelineTreeWidget::update(const std::vector<AbstractPipeline*>& pipelines) {
_treeModel->setData(pipelines);
}
void PipelineTreeWidget::setupWidget() {
_treeModel = new PipelineTreeModel(this);
tgtAssert(_treeModel != 0, "Failed creating TreeViewWidget model.");
setModel(_treeModel);
resizeColumnToContents(0);
}
}
\ No newline at end of file
#ifndef PIPELINETREEWIDGET_H__
#define PIPELINETREEWIDGET_H__
#include <QAbstractItemModel>
#include <QTreeWidget>
#include <QList>
#include <QVariant>
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/abstractprocessor.h"
#include <vector>
namespace TUMVis {
// = TreeModel items ==============================================================================
class TreeItem {
public:
TreeItem(TreeItem* parent = 0);
virtual ~TreeItem();
virtual QVariant getData(int column) const = 0;
TreeItem* getParent();
TreeItem* getChild(int row);
int getRow();
int getChildCount();
private:
TreeItem* _parent;
QList<TreeItem*> _children;
};
class RootTreeItem : public TreeItem {
public:
RootTreeItem(TreeItem* parent = 0);
virtual ~RootTreeItem();
virtual QVariant getData(int column) const;
};
class PipelineTreeItem : public TreeItem {
public:
PipelineTreeItem(AbstractPipeline* pipeline, TreeItem* parent);
virtual ~PipelineTreeItem();
virtual QVariant getData(int column) const;
private:
AbstractPipeline* _pipeline;
};
class ProcessorTreeItem : public TreeItem {
public:
ProcessorTreeItem(AbstractProcessor* processor, TreeItem* parent);
virtual ~ProcessorTreeItem();
virtual QVariant getData(int column) const;
private:
AbstractProcessor* _processor;
};
// = TreeModel ====================================================================================
class PipelineTreeModel : public QAbstractItemModel {
Q_OBJECT
public:
PipelineTreeModel(QObject *parent = 0);
~PipelineTreeModel();
void setData(const std::vector<AbstractPipeline*>& pipelines);
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
private:
TreeItem* _rootItem;
};
// = Widget =======================================================================================
class PipelineTreeWidget : public QTreeView {
Q_OBJECT;
public:
PipelineTreeWidget(QWidget* parent = 0);
virtual ~PipelineTreeWidget();
public slots:
void update(const std::vector<AbstractPipeline*>& pipelines);
private:
void setupWidget();
PipelineTreeModel* _treeModel;
};
}
#endif // PIPELINETREEWIDGET_H__
......@@ -3,10 +3,6 @@
using namespace TUMVis;
SliceVis* sliceVis = 0;
TumVisPainter* painter = 0;
PipelineEvaluator* pe;
/**
* TUMVis main function, application entry point
*
......
......@@ -3,6 +3,7 @@
#include "tgt/assert.h"
#include "tgt/exception.h"
#include "tgt/glcontext.h"
#include "tgt/gpucapabilities.h"
#include "tgt/shadermanager.h"
#include "tgt/qt/qtapplication.h"
#include "tgt/qt/qtthreadedcanvas.h"
......@@ -10,21 +11,28 @@
#include "tbb/include/tbb/compat/thread"
#include "application/tumvispainter.h"
#include "application/gui/mainwindow.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/visualizationpipeline.h"
#include "core/pipeline/pipelineevaluator.h"
namespace TUMVis {
const std::string TumVisApplication::loggerCat_ = "TUMVis.application.TumVisApplication";
TumVisApplication::TumVisApplication(int argc, char** argv)
: QApplication(argc, argv)
, _localContext(0)
, _mainWindow(0)
, _initialized(false)
, _argc(argc)
, _argv(argv)
{
tgt::QtContextManager::init();
// Make Xlib and GLX thread safe under X11
QApplication::setAttribute(Qt::AA_X11InitThreads);
_mainWindow = new MainWindow(this);
tgt::QtContextManager::init();
}
TumVisApplication::~TumVisApplication() {
......@@ -41,6 +49,7 @@ namespace TUMVis {
delete *it;
}
// TODO: _mainWindow is a Qt pointer and does not need to be deleted - right?
}
void TumVisApplication::init() {
......@@ -57,6 +66,14 @@ namespace TUMVis {
tgt::initGL(featureset);
LGL_ERROR;
// ensure matching OpenGL specs
if (GpuCaps.getGlVersion() < tgt::GpuCapabilities::GlVersion::TGT_GL_VERSION_3_0) {
LERROR("Your system does not support OpenGL 3.0, which is mandatory. TUMVis will probably not work as intendet.");
}
if (GpuCaps.getShaderVersion() < tgt::GpuCapabilities::GlVersion::SHADER_VERSION_130) {
LERROR("Your system does not support GLSL Shader Version 1.30, which is mandatory. TUMVis will probably not work as intendet.");
}
if (_argc > 0) {
// ugly hack
std::string programPath(_argv[0]);
......@@ -105,6 +122,8 @@ namespace TUMVis {
// disconnect OpenGL context from this thread so that the other threads can acquire an OpenGL context.
CtxtMgr.releaseCurrentContext();
_mainWindow->show();
// Start evaluator/render threads
for (std::vector<PipelineEvaluator*>::iterator it = _pipelineEvaluators.begin(); it != _pipelineEvaluators.end(); ++it) {
(*it)->start();
......@@ -128,21 +147,20 @@ namespace TUMVis {
}
void TumVisApplication::addPipeline(AbstractPipeline* pipeline) {
tgtAssert(_initialized == false, "Adding pipelines after initialization is currently not supported.");
tgtAssert(pipeline != 0, "Pipeline must not be 0.");
_pipelines.push_back(pipeline);
PipelineEvaluator* pe = new PipelineEvaluator(pipeline);
_pipelineEvaluators.push_back(pe);
s_PipelinesChanged();
}
void TumVisApplication::addVisualizationPipeline(const std::string& name, VisualizationPipeline* vp) {
tgtAssert(_initialized == false, "Adding pipelines after initialization is currently not supported.");
tgtAssert(vp != 0, "Pipeline must not be 0.");
// TODO: is there a more leightweight method to create a context for the pipeline (just performing off-screen rendering)?
tgt::QtThreadedCanvas* evaluationContext = CtxtMgr.createContext(name + "_eval", "", tgt::ivec2(512, 512));
vp->setCanvas(evaluationContext);
addPipeline(vp);
// create canvas and painter for the VisPipeline and connect all together
tgt::QtThreadedCanvas* canvas = CtxtMgr.createContext(name, "TUMVis", tgt::ivec2(512, 512));
canvas->init();
......@@ -152,6 +170,11 @@ namespace TUMVis {
CtxtMgr.releaseCurrentContext();
_visualizations.push_back(std::make_pair(vp, painter));
// TODO: is there a more leightweight method to create a context for the pipeline (just performing off-screen rendering)?
tgt::QtThreadedCanvas* evaluationContext = CtxtMgr.createContext(name + "_eval", "", tgt::ivec2(512, 512));
vp->setCanvas(evaluationContext);
addPipeline(vp);
}
}
\ No newline at end of file
#ifndef TUMVISAPPLICATION_H__
#define TUMVISAPPLICATION_H__
#include "sigslot/sigslot.h"
#include <QApplication>
#include <utility>
#include <vector>
......@@ -11,6 +12,7 @@ namespace tgt {
namespace TUMVis {
class AbstractPipeline;
class MainWindow;
class PipelineEvaluator;
class TumVisPainter;
class VisualizationPipeline;
......@@ -28,6 +30,8 @@ namespace TUMVis {
* 6) You can now safely destroy your TumVisApplication
*/
class TumVisApplication : QApplication {
friend class MainWindow;
public:
/**
* Creates a new TumVisApplication.
......@@ -80,22 +84,28 @@ namespace TUMVis {
*/
int run();
sigslot::signal0<> s_PipelinesChanged;
private:
/// All pipelines (incuding VisualizationPipelines)
std::vector<AbstractPipeline*> _pipelines;
/// All pipeline evaluators
/// All pipeline evaluators (separated from _pipelines because we probably want multiple pipelines per evaluator later)
std::vector<PipelineEvaluator*> _pipelineEvaluators;
/// All visualisations (i.e. VisualizationPipelines with their corresponding painters/canvases)
std::vector< std::pair<VisualizationPipeline*, TumVisPainter*> > _visualizations;
/// A local OpenGL context used for initialization
tgt::QtThreadedCanvas* _localContext;
/// Main window hosting GUI stuff
MainWindow* _mainWindow;
/// Flag, whether TumVisApplication was correctly initialized
bool _initialized;
int _argc;
char** _argv;
static const std::string loggerCat_;
};
}
......
......@@ -60,4 +60,8 @@ namespace TUMVis {
return _invalidationLevel;
}
const std::vector<AbstractProcessor*>& AbstractPipeline::getProcessors() const {
return _processors;
}
}
......@@ -65,6 +65,18 @@ namespace TUMVis {
* \return _data
*/
const DataContainer& getDataContainer() const;