Commit c0bbd5c5 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'refactor-packages' into 'development'

Refactor packages

See merge request !117
parents a26fa8dc a841f8d0
#
# CAMPVis - Yet another visualization framework
# CMake file inspired by Voreen
#
# = CAMPVis - Yet another medical visualization framework =====================
PROJECT(CAMPVis)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
#
# Global Build Options
#
SET(CAMPVIS_VERSION 1.0.0)
# = Global Build Options ======================================================
OPTION(BUILD_SHARED_LIBS "Build shared libraries (strongly recommended!)" ON)
#OPTION(CAMPVIS_PRECOMPILED_HEADER "Use pre-compiled headers?" ON)
OPTION(CAMPVIS_DEBUG "Activate debug code?" ON)
OPTION(CAMPVIS_BUILD_APPLICATION "Build CAMPVis Application" ON)
OPTION(CAMPVIS_BUILD_CORE "Build CAMPVis Core" ON)
OPTION(CAMPVIS_BUILD_MODULES "Build CAMPVis Modules" ON)
OPTION(CAMPVIS_ENABLE_SCRIPTING "Add support for scripting CAMPVis using Lua" OFF)
OPTION(CAMPVIS_BUILD_LIB_CGT "Build CGT Library" ON)
OPTION(CAMPVIS_BUILD_LIB_LUA "Build Lua Library" OFF)
OPTION(CAMPVIS_BUILD_DOXYGEN "Build Doxygen Documentation" OFF)
OPTION(CAMPVIS_DEPLOY_SHADERS "Deploy Shader files to binary directory" OFF)
OPTION(CAMPVIS_GROUP_SOURCE_FILES "Group source files by directory" ON)
OPTION(CAMPVIS_BUILD_GOOGLETEST "Build googletest library" OFF)
OPTION(CAMPVIS_BUILD_TEST_SOURCES "Build Unit Tests of gooogletest" OFF)
OPTION(CAMPVIS_ENABLE_TESTING "Build CAMPVis Unit Tests using gooogletest" OFF)
IF(WIN32)
OPTION(CAMPVIS_COPY_EXTERNAL_DLLS "Copy external DLLs to bin directory?" ON)
......@@ -32,46 +22,46 @@ IF(WIN32)
OPTION(CAMPVIS_GENERATE_MANIFEST "Generate manifest in Visual Studio debug builds (switch on when encountering errors using incremental linking)?" OFF)
ENDIF()
# = Further Build Options =====================================================
SET(CAMPVIS_DEFAULT_ENABLED_MODULES "STABLE_NO_DEPENDENCIES" CACHE STRING "Default CAMPVis modules to activate")
SET_PROPERTY(CACHE CAMPVIS_DEFAULT_ENABLED_MODULES PROPERTY STRINGS "NONE" "STABLE_NO_DEPENDENCIES" "STABLE_WITH_EXTERNAL_DEPENDENCIES" "TESTING" "ALL")
#
# Further Build Configurations
#
# propagate CAMPVIS_ENABLE_SCRIPTING to CAMPVIS_BUILD_LIB_LUA to support deprecated code
IF (CAMPVIS_ENABLE_SCRIPTING)
SET(CAMPVIS_BUILD_LIB_LUA ON)
ENDIF()
include(cmake/commonconf.cmake)
include(cmake/parseModulesDir.cmake)
# = Start the definition of all CAMPVis targets ===============================
MESSAGE(STATUS "--------------------------------------------------------------------------------")
IF(CAMPVIS_BUILD_LIB_CGT)
ADD_SUBDIRECTORY(ext/cgt)
ADD_SUBDIRECTORY(ext/sigslot)
# cgt, sigslot and campvis-core are enabled by default.
ADD_SUBDIRECTORY(ext/cgt)
ADD_SUBDIRECTORY(ext/sigslot)
ADD_SUBDIRECTORY(core)
IF(CAMPVIS_BUILD_MODULES)
ADD_SUBDIRECTORY(modules)
ENDIF()
IF(CAMPVIS_BUILD_LIB_LUA)
# build scripting targets when enabled
IF(CAMPVIS_ENABLE_SCRIPTING)
# build Lua from source
IF(WIN32)
# Keep LUA_BUILD_AS_DLL in sync with BUILD_SHARED_LIBS
SET(LUA_BUILD_AS_DLL ${BUILD_SHARED_LIBS} CACHE BOOL "Build Lua library as DLL" FORCE)
ENDIF(WIN32)
ADD_SUBDIRECTORY(ext/lua EXCLUDE_FROM_ALL)
# If the above command failed, provide a hint how to fix the problem
IF(NOT TARGET liblua)
MESSAGE(SEND_ERROR "Did you forget to run `git submodule update --init`?")
ENDIF(NOT TARGET liblua)
ENDIF()
IF(CAMPVIS_BUILD_CORE)
ADD_SUBDIRECTORY(core)
ENDIF()
IF(CAMPVIS_BUILD_MODULES)
ADD_SUBDIRECTORY(modules)
ENDIF()
IF(CAMPVIS_ENABLE_SCRIPTING)
# First, find Lua to setup paths for all projects correctly
FIND_PACKAGE(Lua REQUIRED)
IF(LUA_FOUND)
......@@ -91,22 +81,44 @@ IF(CAMPVIS_BUILD_APPLICATION)
ADD_SUBDIRECTORY(application)
ENDIF()
IF(CAMPVIS_BUILD_GOOGLETEST)
# build campvis-test when enabled
IF(CAMPVIS_ENABLE_TESTING)
ADD_SUBDIRECTORY(ext/gtest-1.7.0)
ENDIF()
IF(CAMPVIS_BUILD_TEST_SOURCES)
ADD_SUBDIRECTORY(test)
ENDIF()
# build doxygen when enabled
IF(CAMPVIS_BUILD_DOXYGEN)
ADD_SUBDIRECTORY(doc EXCLUDE_FROM_ALL)
ENDIF()
#
# Copy External DLLs
#
MESSAGE(STATUS "--------------------------------------------------------------------------------")
MESSAGE(STATUS "Finishing up")
# = Export all CAMPVis Targets so that they can be included easily ============
# write package version file
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/CAMPVisConfigVersion.cmake"
VERSION ${CAMPVIS_VERSION}
COMPATIBILITY AnyNewerVersion
)
# write campvis targets file
export(EXPORT campvis-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/CAMPVisTargets.cmake"
# NAMESPACE Upstream::
)
# write campvis configuration file
configure_file("${CampvisHome}/cmake/CAMPVisConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/CAMPVisConfig.cmake"
@ONLY
)
#INSTALL(EXPORT campvis-targets NAMESPACE Upstream:: DESTINATION ${CampvisLibInstallDir})
EXPORT(PACKAGE CAMPVis)
# = Copy Windows DLLs to binary dir for improved development experience =======
IF(WIN32)
# gather Qt4 DLLs - TODO: remove redundant naming of required components
FIND_PACKAGE(Qt4DLLs COMPONENTS QtCore QtGui QtOpenGL QtNetwork QtXmlPatterns)
......@@ -120,3 +132,5 @@ IF(WIN32)
COPY_EXTERNAL_DLLS(CampvisExternalDllsDebug CampvisExternalDllsRelease false)
ENDIF()
ENDIF()
MESSAGE(STATUS "--------------------------------------------------------------------------------")
......@@ -2,7 +2,7 @@ PROJECT(campvis-application)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0 FATAL_ERROR)
INCLUDE(../cmake/commonconf.cmake)
MESSAGE(STATUS "Configuring CAMPVis Application")
MESSAGE(STATUS "Configuring CAMPVis-Application")
FILE(GLOB CampvisApplicationSources
*.cpp
......@@ -28,7 +28,6 @@ FILE(GLOB CampvisApplicationForms
)
SET(CampvisApplicationToBeMocced
qtjobprocessor.h
gui/mainwindow.h
gui/datacontainerinspectorcanvas.h
gui/datacontainerinspectorwidget.h
......@@ -64,8 +63,9 @@ SET(CampvisApplicationToBeMocced
gui/properties/stringpropertywidget.h
gui/properties/statuspropertywidget.h
gui/properties/transferfunctionpropertywidget.h
tools/qtexteditlog.h
tools/bufferinglog.h
tools/qtjobprocessor.h
tools/qtexteditlog.h
)
......
......@@ -34,6 +34,9 @@ using namespace campvis;
* \return 0 if program exited successfully
**/
int main(int argc, char** argv) {
// Make Xlib and GLX thread safe under X11
QCoreApplication::setAttribute(Qt::AA_X11InitThreads);
CampVisApplication app(argc, argv);
app.init();
int toReturn = app.run();
......
......@@ -35,21 +35,22 @@
#include "cgt/texturereadertga.h"
#include "cgt/qt/qtthreadedcanvas.h"
#include "application/campvispainter.h"
#include "application/gui/properties/propertywidgetfactory.h"
#include "application/gui/mainwindow.h"
#include "application/gui/mdi/mdidockablewindow.h"
#include "core/init.h"
#include "core/tools/simplejobprocessor.h"
#include "core/tools/stringutils.h"
#include "core/tools/quadrenderer.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/abstractworkflow.h"
#include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/pipelinepainter.h"
#include "core/datastructures/imagerepresentationconverter.h"
#include "core/pipeline/visualizationprocessor.h"
#include "modules/pipelinefactory.h"
#include "qtjobprocessor.h"
#include "application/tools/qtjobprocessor.h"
#include <QApplication>
......@@ -71,106 +72,62 @@ namespace campvis {
, _argc(argc)
, _argv(argv)
{
// Make Xlib and GLX thread safe under X11
QApplication::setAttribute(Qt::AA_X11InitThreads);
sigslot::signal_manager::init();
sigslot::signal_manager::getRef().start();
cgt::GlContextManager::init();
OpenGLJobProcessor::init();
SimpleJobProcessor::init();
QtJobProcessor::init();
}
CampVisApplication::~CampVisApplication() {
cgtAssert(_initialized == false, "Destructing initialized CampVisApplication, deinitialize first!");
sigslot::signal_manager::getRef().stop();
sigslot::signal_manager::deinit();
}
void CampVisApplication::init() {
cgtAssert(_initialized == false, "Tried to initialize CampVisApplication twice.");
// Init CGT
cgt::InitFeature::Features featureset = cgt::InitFeature::ALL;
cgt::init(featureset);
LogMgr.getConsoleLog()->addCat("", true);
_mainWindow = new MainWindow(this);
// create a local OpenGL context and init GL
_localContext = new QtThreadedCanvas("", cgt::ivec2(16, 16));
cgt::GlContextManager::getRef().registerContextAndInitGlew(_localContext, "Local Context");
cgt::initGL(featureset);
ShdrMgr.setDefaultGlslVersion("330");
LGL_ERROR;
QuadRenderer::init();
std::vector<std::string> searchPaths;
if (_argc > 0) {
// ugly hack
std::string basePath(_argv[0]);
basePath = cgt::FileSystem::parentDir(basePath);
ShdrMgr.addPath(basePath);
ShdrMgr.addPath(basePath + "/core/glsl");
basePath = cgt::FileSystem::parentDir(cgt::FileSystem::parentDir(basePath));
ShdrMgr.addPath(basePath);
ShdrMgr.addPath(basePath + "/core/glsl");
searchPaths.push_back(cgt::FileSystem::parentDir(basePath));
searchPaths.push_back(cgt::FileSystem::parentDir(cgt::FileSystem::parentDir(basePath)));
#ifdef CAMPVIS_SOURCE_DIR
{
std::string sourcePath = CAMPVIS_SOURCE_DIR;
ShdrMgr.addPath(sourcePath);
ShdrMgr.addPath(sourcePath + "/core/glsl");
}
searchPaths.push_back(CAMPVIS_SOURCE_DIR);
#endif
}
_mainWindow->init();
// ensure matching OpenGL specs
LINFO("Using Graphics Hardware " << GpuCaps.getVendorAsString() << " " << GpuCaps.getGlRendererString() << " on " << GpuCaps.getOSVersionString());
LINFO("Supported OpenGL " << GpuCaps.getGlVersion() << ", GLSL " << GpuCaps.getShaderVersion());
if (GpuCaps.getGlVersion() < cgt::GpuCapabilities::GlVersion::CGT_GL_VERSION_3_3) {
LERROR("Your system does not support OpenGL 3.3, which is mandatory. CAMPVis will probably not work as intended.");
}
if (GpuCaps.getShaderVersion() < cgt::GpuCapabilities::GlVersion::SHADER_VERSION_330) {
LERROR("Your system does not support GLSL Shader Version 3.30, which is mandatory. CAMPVis will probably not work as intended.");
}
_localContext = new QtThreadedCanvas("", cgt::ivec2(16, 16));
campvis::init(_localContext, searchPaths);
// load textureData from file
cgt::TextureReaderTga trt;
_errorTexture = trt.loadTexture(ShdrMgr.completePath("application/data/no_input.tga"), cgt::Texture::LINEAR);
_mainWindow = new MainWindow(this);
cgt::GLContextScopedLock lock(_localContext);
{
_mainWindow->init();
// load textureData from file
cgt::TextureReaderTga trt;
_errorTexture = trt.loadTexture(ShdrMgr.completePath("application/data/no_input.tga"), cgt::Texture::LINEAR);
#ifdef CAMPVIS_HAS_SCRIPTING
// create and store Lua VM for this very pipeline
_luaVmState = new LuaVmState();
_luaVmState->redirectLuaPrint();
// Let Lua know where CAMPVis modules are located
if (! _luaVmState->execString("package.cpath = '" CAMPVIS_LUA_MODS_PATH "'"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("package.path = package.path .. ';" CAMPVIS_LUA_SCRIPTS_PATH "'"))
LERROR("Error setting up Lua VM.");
// Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
if (! _luaVmState->execString("require(\"campvis\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("require(\"cgt\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("pipelines = {}"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("inspect = require 'inspect'"))
LERROR("Error setting up Lua VM.");
// create and store Lua VM for this very pipeline
_luaVmState = new LuaVmState();
_luaVmState->redirectLuaPrint();
// Let Lua know where CAMPVis modules are located
if (! _luaVmState->execString("package.cpath = '" CAMPVIS_LUA_MODS_PATH "'"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("package.path = package.path .. ';" CAMPVIS_LUA_SCRIPTS_PATH "'"))
LERROR("Error setting up Lua VM.");
// Load CAMPVis' core Lua module to have SWIG glue for AutoEvaluationPipeline available
if (! _luaVmState->execString("require(\"campvis\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("require(\"cgt\")"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("pipelines = {}"))
LERROR("Error setting up Lua VM.");
if (! _luaVmState->execString("inspect = require 'inspect'"))
LERROR("Error setting up Lua VM.");
#endif
GLCtxtMgr.releaseContext(_localContext, false);
}
// parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments();
......@@ -207,10 +164,7 @@ namespace campvis {
addPipeline(pipelinesToAdd[i].toStdString(), p);
}
}
GLJobProc.setContext(_localContext);
GLJobProc.start();
_initialized = true;
}
......@@ -218,8 +172,8 @@ namespace campvis {
cgtAssert(_initialized, "Tried to deinitialize uninitialized CampVisApplication.");
// Stop all pipeline threads.
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
it->_pipeline->stop();
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
(*it)->stop();
}
for (auto it = _workflows.begin(); it != _workflows.end(); ++it)
......@@ -232,39 +186,23 @@ namespace campvis {
delete _errorTexture;
// Deinit pipeline and painter first
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
it->_pipeline->deinit();
it->_painter->deinit();
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
(*it)->deinit();
}
_mainWindow->deinit();
QuadRenderer::deinit();
}
// now delete everything in the right order:
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete it->_painter;
delete it->_pipeline;
}
for (std::vector<DataContainer*>::iterator it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete *it;
}
{
// Deinit everything OpenGL using the local context.
cgt::GLContextScopedLock lock(_localContext);
cgt::deinitGL();
for (auto it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
delete *it;
}
GLJobProc.stop();
OpenGLJobProcessor::deinit();
SimpleJobProcessor::deinit();
cgt::GlContextManager::deinit();
cgt::deinit();
campvis::deinit();
PropertyWidgetFactory::deinit();
ImageRepresentationConverter::deinit();
PipelineFactory::deinit();
_initialized = false;
......@@ -291,14 +229,10 @@ namespace campvis {
cgt::QtThreadedCanvas* canvas = new cgt::QtThreadedCanvas("CAMPVis", cgt::ivec2(512, 512));
canvas->init();
CampVisPainter* painter = new CampVisPainter(canvas, pipeline);
canvas->setPainter(painter, false);
pipeline->setCanvas(canvas);
painter->setErrorTexture(_errorTexture);
PipelineRecord pr = { pipeline, painter };
_pipelines.push_back(pr);
pipeline->getPipelinePainter()->setErrorTexture(_errorTexture);
_pipelines.push_back(pipeline);
_pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(name, canvas);
// initialize context (GLEW) and pipeline in OpenGL thread)
......@@ -325,8 +259,6 @@ namespace campvis {
pipeline->init();
LGL_ERROR;
canvas->getPainter()->init();
LGL_ERROR;
// enable pipeline and invalidate all processors
pipeline->setEnabled(true);
......@@ -362,8 +294,8 @@ namespace campvis {
LINFO("Rebuilding shaders from file successful.");
}
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
for (std::vector<AbstractProcessor*>::const_iterator pit = it->_pipeline->getProcessors().begin(); pit != it->_pipeline->getProcessors().end(); ++pit) {
for (auto it = _pipelines.begin(); it != _pipelines.end(); ++it) {
for (auto pit = (*it)->getProcessors().cbegin(); pit != (*it)->getProcessors().cend(); ++pit) {
if (VisualizationProcessor* tester = dynamic_cast<VisualizationProcessor*>(*pit)) {
tester->invalidate(AbstractProcessor::INVALID_RESULT);
}
......
......@@ -50,7 +50,6 @@ namespace campvis {
class AbstractPipeline;
class AbstractWorkflow;
class MainWindow;
class CampVisPainter;
class MdiDockableWindow;
class LuaVmState;
......@@ -70,12 +69,6 @@ namespace campvis {
friend class MainWindow;
public:
/// Record storing a pipeline together with its painter and Lua VM state.
struct PipelineRecord {
AbstractPipeline* _pipeline;
CampVisPainter* _painter;
};
/**
* Creates a new CampVisApplication.
* \param argc number of passed arguments
......@@ -167,7 +160,7 @@ namespace campvis {
std::vector<AbstractWorkflow*> _workflows;
/// All pipelines
std::vector<PipelineRecord> _pipelines;
std::vector<AbstractPipeline*> _pipelines;
/// Map of all pipelines with their MDI windows
std::map<AbstractPipeline*, MdiDockableWindow*> _pipelineWindows;
......
......@@ -63,7 +63,7 @@ namespace campvis {
* Creates a new AbstractAdjusterWidget.
* \param parent parent Qt widget
*/
AbstractAdjusterWidget(QWidget* parent = 0);
explicit AbstractAdjusterWidget(QWidget* parent = 0);
/**
* Return the adjuster's current value.
......
......@@ -43,7 +43,7 @@ namespace campvis {
* Creates a new DoubleAdjusterWidget.
* \param parent parent Qt widget
*/
DoubleAdjusterWidget(QWidget* parent = 0);
explicit DoubleAdjusterWidget(QWidget* parent = 0);
/**
* Returns how many decimals the adjuster will use for displaying and doubleerpreting doubles.
......
......@@ -42,7 +42,7 @@ namespace campvis {
* Creates a new IntAdjusterWidget.
* \param parent Parent Qt widget
*/
IntAdjusterWidget(QWidget* parent = 0);
explicit IntAdjusterWidget(QWidget* parent = 0);
/**
* Change the adjuster's current value.
......
......@@ -55,6 +55,7 @@ namespace campvis {
, p_renderAChannel("RenderAChannel", "Render Alpha Channel", true)
, p_geometryRendererProperties("GeometryRendererProperties", "GeometryRenderer Properties")
, _texturesDirty(true)
, _geometriesDirty(true)
, _dataContainer(nullptr)
, _paintShader(nullptr)
, _quad(nullptr)
......@@ -114,7 +115,7 @@ namespace campvis {
createQuad();
// set this as painter to get notified when window size changes
setPainter(this, false);
setPainter(this);
getEventHandler()->addEventListenerToFront(this);
_geometryRenderer.init();
......@@ -252,9 +253,10 @@ namespace campvis {
if (_quad != 0 && _paintShader != 0) {
// avoid recursive paints.
if (! cgt::GlContextManager::getRef().checkWhetherThisThreadHasAcquiredOpenGlContext()) {
// TODO: check, whether this should be done in an extra thread
cgt::GLContextScopedLock lock(this);
paint();
std::thread([this] () {
cgt::GLContextScopedLock lock(this);
paint();
});
}
}
}
......
......@@ -35,8 +35,9 @@
#include "core/datastructures/datacontainer.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/pipeline/pipelinefactory.h"
#include "core/pipeline/processorfactory.h"
#include "core/tools/stringutils.h"
#include "modules/pipelinefactory.h"
#include <QScrollBar>
#include <QFileDialog>
......@@ -239,17 +240,11 @@ namespace campvis {
}
void MainWindow::onPipelinesChanged() {
std::vector<AbstractPipeline*> pipelines;
std::for_each(_application->_pipelines.begin(), _application->_pipelines.end(), [&] (const CampVisApplication::PipelineRecord& pr) { pipelines.push_back(pr._pipeline); });
emit updatePipelineWidget(_application->_dataContainers, pipelines);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
}
void MainWindow::onDataContainersChanged() {
std::vector<AbstractPipeline*> pipelines;
std::for_each(_application->_pipelines.begin(), _application->_pipelines.end(), [&] (const CampVisApplication::PipelineRecord& pr) { pipelines.push_back(pr._pipeline); });
emit updatePipelineWidget(_application->_dataContainers, pipelines);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
}
void MainWindow::onPipelineWidgetItemChanged(const QModelIndex& index) {
......@@ -439,10 +434,7 @@ namespace campvis {
p->init();
_selectedPipeline->addProcessor(p);
std::vector<AbstractPipeline*> pipelines;
std::for_each(_application->_pipelines.begin(), _application->_pipelines.end(), [&] (const CampVisApplication::PipelineRecord& pr) { pipelines.push_back(pr._pipeline); });
emit updatePipelineWidget(_application->_dataContainers, pipelines);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
}
void MainWindow::onRebuildShadersClicked() {
......
......@@ -59,7 +59,6 @@ namespace campvis {
}
_property->s_changed.connect(this, &AbstractPropertyWidget::onPropertyChanged);
// cppcheck-suppress pureVirtualCall
connect(this, SIGNAL(s_propertyChanged(const AbstractProperty*)), this, SLOT(updateWidgetFromProperty()));
}
......
......@@ -82,7 +82,7 @@ namespace campvis {
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void updateWidgetFromProperty() = 0;
virtual void updateWidgetFromProperty() {};