diff --git a/.gitsubprojects b/.gitsubprojects
index 3a7d14af0b0b382a2230eb75d0fa332635bed47c..70e741d5bdcc37179b1ef17f7631eec2c3818512 100644
--- a/.gitsubprojects
+++ b/.gitsubprojects
@@ -4,3 +4,4 @@
# git_subproject(Lexis https://github.com/HBPVis/Lexis.git 617eedb)
# git_subproject(gmrvlex git@gitlab.gmrv.es:nsviz/gmrvlex.git c20b194)
git_subproject(neurolots https://github.com/gmrvvis/neurolots.git 2a1cfeb9)
+git_subproject( acuterecorder https://github.com/vg-lab/AcuteRecorder.git 3fe7d5ba)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 13cffaddc54f041a8b0e0122363f1357bd376461..05fb8820fff43bac5ab9afaed00e20afd5f28023 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,7 +5,7 @@
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
-project(neurotessmesh VERSION 0.1.1)
+project(neurotessmesh VERSION 0.2.0)
set(neurotessmesh_VERSION_ABI 1)
# Disable in source building
@@ -55,8 +55,9 @@ common_find_package(ZeroEQ ${NEUROTESSMESH_OPTS_FIND_ARGS})
common_find_package(gmrvlex ${NEUROTESSMESH_OPTS_FIND_ARGS})
common_find_package(GLUT SYSTEM)
common_find_package(Boost COMPONENTS system filesystem SYSTEM)
+common_find_package( acuterecorder REQUIRED )
-list(APPEND NEUROTESSMESH_DEPENDENT_LIBRARIES Qt5Core Qt5Widget Qt5OpenGL GLEW neurolots)
+list(APPEND NEUROTESSMESH_DEPENDENT_LIBRARIES Qt5Core Qt5Widget Qt5OpenGL GLEW neurolots acuterecorder)
if ( ZEROEQ_FOUND )
common_find_package(Threads REQUIRED)
diff --git a/Changelog.md b/Changelog.md
index 7b2b102b60490b78e3e0c24c85c84ae2de16e4a8..2c63357b74672ca83aef1be6b3e9495eb3c836aa 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,10 @@
## git master
+## version 0.2.0
+
+* [!15] Added a recorder option, which allows users to record the application.
+
## version 0.0.1
* [!3] Updated Changelog and version. Release 0.0.1 preparation.
diff --git a/neurotessmesh/CMakeLists.txt b/neurotessmesh/CMakeLists.txt
index e382ba7dc702f5eb5f40fb37b71535dbbaf7f42e..06293939f263035bc380924d6c35da35dbb1de8b 100644
--- a/neurotessmesh/CMakeLists.txt
+++ b/neurotessmesh/CMakeLists.txt
@@ -46,6 +46,7 @@ set( NEUROTESSMESH_LINK_LIBRARIES
nlgeometry
nlgenerator
nlrender
+ acuterecorder
)
diff --git a/neurotessmesh/ColorSelectionWidget.cpp b/neurotessmesh/ColorSelectionWidget.cpp
index d201277af1a7267e62a74941aa6d2c34c75dcc6d..8f395ec1e4ce603a4651747dac87cba9993fa51b 100644
--- a/neurotessmesh/ColorSelectionWidget.cpp
+++ b/neurotessmesh/ColorSelectionWidget.cpp
@@ -43,6 +43,7 @@ void ColorSelectionWidget::mousePressEvent( QMouseEvent* /*event*/ )
{
_color = newColor;
emit this->colorChanged( _color );
+ repaint();
}
}
@@ -50,4 +51,5 @@ void ColorSelectionWidget::color( const QColor& color_ )
{
_color = color_;
emit this->colorChanged( _color );
+ repaint();
}
diff --git a/neurotessmesh/MainWindow.cpp b/neurotessmesh/MainWindow.cpp
index c87d85e22f1c96814c469f13f4a538e5b2b7f224..421e2cd9815cb050b86326db61aa8119fb133bf3 100644
--- a/neurotessmesh/MainWindow.cpp
+++ b/neurotessmesh/MainWindow.cpp
@@ -19,6 +19,8 @@
#include <deflect/version.h>
#endif
+#include <acuterecorder/acuterecorder.h>
+
#include <QFileDialog>
#include <QInputDialog>
#include <QMessageBox>
@@ -30,6 +32,7 @@ MainWindow::MainWindow( QWidget* parent_, bool updateOnIdle_ )
, _lastOpenedFileName( "" )
, _ui( new Ui::MainWindow )
, _openGLWidget( nullptr )
+ , _recorder( nullptr )
{
_ui->setupUi( this );
@@ -138,11 +141,14 @@ void MainWindow::init( const std::string& zeqSession_ )
connect( _neuronRender, SIGNAL( currentIndexChanged( int )),
_openGLWidget, SLOT( changeNeuronPiece( int )));
- _neuronRender->setCurrentIndex( 1 );
+ _neuronRender->currentIndexChanged( 1 );
connect( _selectedNeuronRender, SIGNAL( currentIndexChanged( int )),
_openGLWidget, SLOT( changeSelectedNeuronPiece( int )));
_selectedNeuronRender->currentIndexChanged( 0 );
+
+ connect( _ui->actionRecorder , SIGNAL( triggered( void )) , this ,
+ SLOT( openRecorder( void )));
}
void MainWindow::showStatusBarMessage ( const QString& message )
@@ -157,6 +163,8 @@ void MainWindow::openBlueConfig( const std::string& fileName,
neurotessmesh::Scene::TDataFileType::BlueConfig,
targetLabel );
updateNeuronList( );
+ _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
+ _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
}
void MainWindow::openXMLScene( const std::string& fileName )
@@ -164,6 +172,8 @@ void MainWindow::openXMLScene( const std::string& fileName )
_openGLWidget->loadData( fileName,
neurotessmesh::Scene::TDataFileType::NsolScene );
updateNeuronList( );
+ _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
+ _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
}
void MainWindow::openSWCFile( const std::string& fileName )
@@ -171,6 +181,8 @@ void MainWindow::openSWCFile( const std::string& fileName )
_openGLWidget->loadData( fileName,
neurotessmesh::Scene::TDataFileType::SWC );
updateNeuronList( );
+ _openGLWidget->changeNeuronPiece(_neuronRender->currentIndex());
+ _openGLWidget->changeSelectedNeuronPiece(_selectedNeuronRender->currentIndex());
}
void MainWindow::updateNeuronList( void )
@@ -308,13 +320,58 @@ void MainWindow::showAbout( void )
"<a href=www.gmrv.es>www.gmrv.es</a><br>"
"<a href='mailto:gmrv@gmrv.es'>gmrv@gmrv.es</a><br><br>"
"<br>(C) 2015. Universidad Rey Juan Carlos<br><br>"
- "<img src=':/icons/gmrv_grande.png' > "
- "<img src=':/icons/logoURJC.png' ><br><br> "
+ "<img src=':/icons/rsc/gmrv_grande.png' > "
+ "<img src=':/icons/rsc/logoURJC.png' ><br><br> "
"</p>"
"")
);
}
+void MainWindow::openRecorder( void )
+{
+
+ // The button stops the recorder if found.
+ if( _recorder != nullptr )
+ {
+ _ui->actionRecorder->setDisabled( true );
+ _recorder->stop();
+
+ // Recorder will be deleted after finishing.
+ _recorder = nullptr;
+ _ui->actionRecorder->setChecked( false );
+ return;
+ }
+
+ RSWParameters params;
+ params.widgetsToRecord.emplace_back( "Viewport" , _openGLWidget );
+ params.widgetsToRecord.emplace_back( "Main Widget" , this );
+ params.includeScreens = false;
+
+ if(!_ui->actionAdvancedRecorderOptions->isChecked())
+ {
+ params.showWorker = false;
+ params.showWidgetSourceMode = false;
+ params.showSourceParameters = false;
+ }
+
+ auto dialog = new RecorderDialog( nullptr , params , true );
+ dialog->setWindowIcon( QIcon( ":/icons/rsc/neurotessmesh.png" ));
+ dialog->setFixedSize( 800 , 600 );
+ if ( dialog->exec( ) == QDialog::Accepted)
+ {
+ _recorder = dialog->getRecorder( );
+ connect( _recorder , SIGNAL( finished( )) ,
+ _recorder , SLOT( deleteLater( )));
+ connect( _recorder , SIGNAL( finished( )) ,
+ this , SLOT( finishRecording( )));
+ _ui->actionRecorder->setChecked( true );
+ } else
+ {
+ _ui->actionRecorder->setChecked( false );
+ }
+ dialog->deleteLater( );
+}
+
void MainWindow::updateExtractMeshDock( void )
{
if( _ui->actionEditSave->isChecked( ))
@@ -364,6 +421,11 @@ void MainWindow::onActionGenerate( int /*value_*/ )
_openGLWidget->regenerateNeuronToEdit( alphaRadius, alphaNeurites );
}
+void MainWindow::finishRecording( )
+{
+ _ui->actionRecorder->setEnabled( true );
+}
+
void MainWindow::_generateNeuritesLayout( void )
{
unsigned int numDendrites = _openGLWidget->numNeuritesToEdit( );
diff --git a/neurotessmesh/MainWindow.h b/neurotessmesh/MainWindow.h
index 4143c1e64db88f800d9637d37fe8ed37553201e0..6b8f8f4f0c1997cc4f28a71b3a174b04746efe3d 100644
--- a/neurotessmesh/MainWindow.h
+++ b/neurotessmesh/MainWindow.h
@@ -27,6 +27,8 @@ namespace Ui
class MainWindow;
}
+class Recorder;
+
class MainWindow
: public QMainWindow
{
@@ -56,6 +58,7 @@ public slots:
void openXMLSceneThroughDialog( void );
void openSWCFileThroughDialog( void );
void showAbout( void );
+ void openRecorder( void );
void updateExtractMeshDock( void );
void updateConfigurationDock( void );
@@ -63,6 +66,10 @@ public slots:
void onListClicked( QListWidgetItem *item );
void onActionGenerate( int value_ );
+protected slots:
+
+ void finishRecording( );
+
protected:
QString _lastOpenedFileName;
@@ -100,4 +107,7 @@ private:
QComboBox* _neuronRender;
QComboBox* _selectedNeuronRender;
+
+ // Recorder
+ Recorder* _recorder;
};
diff --git a/neurotessmesh/OpenGLWidget.cpp b/neurotessmesh/OpenGLWidget.cpp
index 8d6d6e25492c194a4a3afe494d265153d3dbbe92..5ff19dde75af751a789bd013f9e21e924d74e617 100644
--- a/neurotessmesh/OpenGLWidget.cpp
+++ b/neurotessmesh/OpenGLWidget.cpp
@@ -13,6 +13,7 @@
#include <QMouseEvent>
#include <QColorDialog>
#include <QFileDialog>
+#include <QMessageBox>
#include <sstream>
#include <string>
#include <iostream>
@@ -67,13 +68,29 @@ OpenGLWidget::~OpenGLWidget( void )
delete _scene;
}
-void OpenGLWidget::loadData(
+bool OpenGLWidget::loadData(
const std::string& fileName_,
const neurotessmesh::Scene::TDataFileType fileType_,
const std::string& target_ )
{
makeCurrent( );
- _scene->loadData( fileName_, fileType_, target_ );
+ const auto errorString = _scene->loadData( fileName_, fileType_, target_ );
+
+ if(!errorString.empty())
+ {
+ const QString message = QString("Error loading file '%1'.\n%2")
+ .arg(QString::fromStdString(fileName_))
+ .arg(QString::fromStdString(errorString));
+
+ QMessageBox msgBox(this);
+ msgBox.setWindowTitle(tr("Error Loading Data"));
+ msgBox.setWindowIcon(QIcon(":/icons/rsc/neurotessmesh.png"));
+ msgBox.setText(message);
+ msgBox.setIcon(QMessageBox::Icon::Critical);
+ msgBox.exec();
+ }
+
+ return errorString.empty();
}
void OpenGLWidget::idleUpdate( bool idleUpdate_ )
@@ -92,7 +109,6 @@ void OpenGLWidget::neuronToEdit( const unsigned int id_ )
update( );
}
-
unsigned int OpenGLWidget::numNeuritesToEdit( void ) const
{
return _scene->numEditMorphologyNeurites( );
@@ -366,7 +382,6 @@ void OpenGLWidget::initializeGL( void )
void OpenGLWidget::paintGL( void )
{
-
makeCurrent( );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
diff --git a/neurotessmesh/OpenGLWidget.h b/neurotessmesh/OpenGLWidget.h
index 2d3693beb59d6bef6f646cb45b8e2e81b1b3e4e3..e92bcbe4a90313e9fd1a71fc5749185932ed712f 100644
--- a/neurotessmesh/OpenGLWidget.h
+++ b/neurotessmesh/OpenGLWidget.h
@@ -44,7 +44,13 @@ public:
~OpenGLWidget( void );
- void loadData( const std::string& fileName_,
+ /** \brief Loads a dataset with the given parameters.
+ * \param[in] fileName_ Dataset filename.
+ * \param[in] fileType_ Dataset type.
+ * \param[in] target_ BlueConfig target if Blueconfig or empty otherwise.
+ *
+ */
+ bool loadData( const std::string& fileName_,
const neurotessmesh::Scene::TDataFileType fileType_ =
neurotessmesh::Scene::TDataFileType::BlueConfig,
const std::string& target_ = std::string( "" ));
diff --git a/neurotessmesh/Scene.cpp b/neurotessmesh/Scene.cpp
index 9eef698572201a85c1f2eb3e6a035a419d8b0c3f..b8b0cf32a851e6b594069f801a18e35552769e87 100644
--- a/neurotessmesh/Scene.cpp
+++ b/neurotessmesh/Scene.cpp
@@ -186,7 +186,7 @@ namespace neurotessmesh
}
}
- void Scene::loadData( const std::string& fileName_,
+ std::string Scene::loadData( const std::string& fileName_,
const TDataFileType fileType_,
#ifdef NSOL_USE_BRION
const std::string& target_
@@ -196,6 +196,7 @@ namespace neurotessmesh
)
{
close( );
+ std::string errorString;
try{
switch( fileType_ )
{
@@ -254,12 +255,16 @@ namespace neurotessmesh
{
std::cerr << "Error: can't load file: " << fileName_ << std::endl;
std::cerr << excep.what( ) << std::endl;
+ errorString = std::string(excep.what());
}
+
generateMeshes( );
_boundingBox = computeBoundingBox( );
_camera->position( _boundingBox.center( ));
_camera->radius( _boundingBox.radius( ) / sin( _camera->camera()->fieldOfView()));
conformRenderTuples( );
+
+ return errorString;
}
void Scene::paintUnselectedSoma( bool paint_ )
diff --git a/neurotessmesh/Scene.h b/neurotessmesh/Scene.h
index 4f54e95d83738ef5be1c02be08b81146d57adcbc..389491335a8f6a38c4713918e0920f5dce4a05a6 100644
--- a/neurotessmesh/Scene.h
+++ b/neurotessmesh/Scene.h
@@ -121,13 +121,14 @@ namespace neurotessmesh
void generateMeshes( void );
/**
- * Method to load neurons data
+ * Method to load neurons data returns an empty string on success
+ * or an error string otherwise.
* @param fileName path to the file
* @param fileType type of file
* @param target to load, specific param to BlueConfig data
*/
NEUROTESSMESH_API
- void loadData( const std::string& fileName_,
+ std::string loadData( const std::string& fileName_,
const TDataFileType fileType_,
const std::string& target_ = std::string( "" ));
diff --git a/neurotessmesh/mainwindow.ui b/neurotessmesh/mainwindow.ui
index 5108201b0d763bdb2ed28abcbd0419f24d28756e..0b1b264c4b2d480a68f2d23ac7e68c62b5f340c8 100644
--- a/neurotessmesh/mainwindow.ui
+++ b/neurotessmesh/mainwindow.ui
@@ -55,6 +55,9 @@
<addaction name="actionRenderOptions"/>
<addaction name="actionEditSave"/>
<addaction name="actionConfiguration"/>
+ <addaction name="separator"/>
+ <addaction name="actionRecorder"/>
+ <addaction name="actionAdvancedRecorderOptions"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuOptions"/>
@@ -81,6 +84,7 @@
<addaction name="actionWireframe"/>
<addaction name="actionCloseData"/>
<addaction name="actionRenderOptions"/>
+ <addaction name="actionRecorder"/>
</widget>
<action name="actionQuit">
<property name="text">
@@ -279,6 +283,32 @@
<string>Ctrl+C</string>
</property>
</action>
+ <action name="actionRecorder">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/rsc/recorder.svg</normaloff>:/icons/rsc/recorder.svg</iconset>
+ </property>
+ <property name="text">
+ <string>Recorder</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+R</string>
+ </property>
+ </action>
+ <action name="actionAdvancedRecorderOptions">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Advanced recorder options</string>
+ </property>
+ <property name="toolTip">
+ <string>Enable advanced recorder options</string>
+ </property>
+ </action>
</widget>
<resources>
<include location="resources.qrc"/>
diff --git a/neurotessmesh/neurotessmesh.cpp b/neurotessmesh/neurotessmesh.cpp
index 26d970cf28db9c3ef35ae2242fc326d2bd2842e1..bc39a29a13c02f9230378d15107113b398185062 100644
--- a/neurotessmesh/neurotessmesh.cpp
+++ b/neurotessmesh/neurotessmesh.cpp
@@ -47,7 +47,7 @@ int main( int argc, char** argv )
std::string zeqUri;
std::string target = std::string( "" );
bool fullscreen = false, initWindowSize = false, initWindowMaximized = false;
- int initWindowWidth, initWindowHeight;
+ int initWindowWidth = 0, initWindowHeight = 0;
int ctxOpenGLMajor = DEFAULT_CONTEXT_OPENGL_MAJOR;
@@ -192,13 +192,13 @@ int main( int argc, char** argv )
usageMessage( argv[0] );
}
- if ( blueConfig != "" )
+ if ( !blueConfig.empty() )
mainWindow->openBlueConfig( blueConfig, target );
- if ( swcFile != "" )
+ if ( !swcFile.empty() )
mainWindow->openSWCFile( swcFile );
- if ( sceneFile != "" )
+ if ( !sceneFile.empty() )
mainWindow->openXMLScene( sceneFile );
}
else
diff --git a/neurotessmesh/resources.qrc b/neurotessmesh/resources.qrc
index 3a7654af86b54d1b5cdc02f47ea6fc19ef068bcf..8f7fe800cc52b4f991a21f51650cd3a52a09e50f 100644
--- a/neurotessmesh/resources.qrc
+++ b/neurotessmesh/resources.qrc
@@ -12,5 +12,7 @@
<file>rsc/reconstruction.png</file>
<file>rsc/home.png</file>
<file>rsc/settings.png</file>
+ <file>rsc/recorder.svg</file>
+ <file>rsc/neurotessmesh.png</file>
</qresource>
</RCC>
diff --git a/neurotessmesh/rsc/recorder.svg b/neurotessmesh/rsc/recorder.svg
new file mode 100644
index 0000000000000000000000000000000000000000..947269bc99779555e5d921b191df4d5d69a1b7e2
--- /dev/null
+++ b/neurotessmesh/rsc/recorder.svg
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="123.49702mm"
+ height="123.49702mm"
+ viewBox="0 0 123.49705 123.49705"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
+ sodipodi:docname="recorder.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#505050"
+ bordercolor="#eeeeee"
+ borderopacity="1"
+ inkscape:pageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="mm"
+ showgrid="false"
+ fit-margin-top="15"
+ fit-margin-left="15"
+ fit-margin-right="15"
+ fit-margin-bottom="15"
+ lock-margins="false"
+ width="107.89702mm"
+ inkscape:zoom="0.74029882"
+ inkscape:cx="-127.65116"
+ inkscape:cy="226.93539"
+ inkscape:window-width="1920"
+ inkscape:window-height="1013"
+ inkscape:window-x="2560"
+ inkscape:window-y="1440"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <defs
+ id="defs2">
+ <filter
+ style="color-interpolation-filters:sRGB"
+ inkscape:label="Blur"
+ id="filter721"
+ x="-0.077007798"
+ y="-0.077007798"
+ width="1.1540156"
+ height="1.1540156">
+ <feGaussianBlur
+ stdDeviation="3 3"
+ result="blur"
+ id="feGaussianBlur719" />
+ </filter>
+ </defs>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-38.877594,-60.209427)">
+ <circle
+ style="fill:#2b0000;fill-rule:evenodd;stroke-width:0.264583;filter:url(#filter721)"
+ id="circle413"
+ cx="106.41572"
+ cy="129.05154"
+ r="46.748512"
+ transform="matrix(0.80142274,0,0,0.80142274,21.131741,25.626701)" />
+ <circle
+ style="fill:#aa0000;fill-rule:evenodd;stroke-width:0.212043"
+ id="path129"
+ cx="101.77579"
+ cy="123.36657"
+ r="37.465321" />
+ </g>
+</svg>