From ca1f4ae22efa640958d28460c8be1197fcbc1a47 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Thu, 31 Oct 2019 19:00:09 +0100 Subject: [PATCH 01/15] NEW MainWindow's central viewer is now a stack widget This simplify the modification of the central viewer (for instance to add a custom viewer easily to camitk-imp or any other camitk::Application --- sdk/libraries/core/application/MainWindow.cpp | 35 ++++++++----------- sdk/libraries/core/application/MainWindow.h | 23 +++++++++--- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/sdk/libraries/core/application/MainWindow.cpp b/sdk/libraries/core/application/MainWindow.cpp index 82c6c52d..8b984b1d 100644 --- a/sdk/libraries/core/application/MainWindow.cpp +++ b/sdk/libraries/core/application/MainWindow.cpp @@ -45,6 +45,7 @@ #include #include #include +#include namespace camitk { // ------------- constructor ----------------- @@ -203,20 +204,6 @@ bool MainWindow::addViewer(Viewer* theViewer) { // ------------- removeViewer ----------------- bool MainWindow::removeViewer(Viewer* viewer) { - if (!viewers.contains(viewer)) { - return false; - } - - // tell all component not to be visible anymore in this viewer - foreach (Component* comp, Application::getAllComponents()) { - comp->setVisibility(viewer, false); - } - - // remove it properly - disconnect(viewer, SIGNAL(selectionChanged()), this, SLOT(refresh())); - viewers.removeAll(viewer); - delete viewer; - return true; } @@ -260,14 +247,20 @@ void MainWindow::addDockViewer(Qt::DockWidgetArea dockingArea, Viewer* theViewer // ------------- setCentralViewer ----------------- void MainWindow::setCentralViewer(Viewer* theViewer) { - if (theViewer->getWidget(this) && addViewer(theViewer)) { - // remove actual central viewer properly - if (centralViewer && (theViewer != centralViewer)) { - removeViewer(centralViewer); + // get the viewer widget (must have something to show as it is a viewer after all!) + QWidget *viewerWidget = theViewer->getWidget(this); + if (viewerWidget != nullptr) { + // add the viewer to the list (if not already in the list) + addViewer(theViewer); + + // if needed, create the default (empty) central widget inside which the central viewers can be added + if (centralWidget()==0) { + setCentralWidget(new QStackedWidget(this)); } - - // set the central widget - setCentralWidget(theViewer->getWidget(this)); + + // add the widget to the central widget + qobject_cast(centralWidget())->addWidget(viewerWidget); + qobject_cast(centralWidget())->setCurrentWidget(viewerWidget); centralViewer = theViewer; } } diff --git a/sdk/libraries/core/application/MainWindow.h b/sdk/libraries/core/application/MainWindow.h index 37125e14..60a172e6 100644 --- a/sdk/libraries/core/application/MainWindow.h +++ b/sdk/libraries/core/application/MainWindow.h @@ -50,14 +50,20 @@ class Viewer; * @ingroup group_sdk_libraries_core_application * * @brief - * This Class is the base class for your application. It sets up the main - * window and providing a menubar, toolbar and statusbar (all hidden). + * This class is the base class for your application. It sets up the main + * window and creates a menubar, toolbar and statusbar (all hidden by default). + * * It is the default main window for a application. * * Create a class that inherits from MainWindow to - * get all the goodies of Core and add your own customization/UI. - * See applications for examples. + * get all the goodies of CamiTK and add your own customization/UI. + * + * See tutorials applications for examples. * + * The central widget is a QStackWidget: when new central viewers are added, the previous central + * viewer is hidden, not destroyed. See the "switchviewer" action tutorial for some example on + * how to embed an new central viewer to the imp main window (and switch back to medical image viewer + * whenever required). */ class CAMITK_API MainWindow : public QMainWindow { Q_OBJECT @@ -184,13 +190,21 @@ protected: /// just call open with the dragged uri void dropEvent(QDropEvent* event) override; + ///@cond /** + * TODO CAMITK_DEPRECATED. This section list all the methods marked as deprecated. They are to be removed in CamiTK 5.0 + * @deprecated + * Removing viewers can be harmful. Central viewer is now simply hidden, therefore there is no need to remove it. + * It will keep itself refreshed and when shown again will be up to date. + * DEPRECATED (CamiTK 5.0) -> to be removed + * * @brief Remove the given viewer from the list of viewer. * @note This tell all Component not to be visible anymore in this viewer instance, remove it from the list of viewers and delete it. * @param viewer The viewer to remove. * @return True if removing succeeded, false otherwise. */ bool removeViewer(Viewer* viewer); + ///@endcond /** * @brief The actual central Viewer. @@ -227,6 +241,7 @@ private: /// the main part of the title QString mainTitle; + }; } -- GitLab From 095e3fa813e9b5fdd7661903a7d1f674e69bd524 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Thu, 31 Oct 2019 19:00:30 +0100 Subject: [PATCH 02/15] FIXED code cleaning --- .../core/viewer/InteractiveViewer.cpp | 224 ++++++++++-------- sdk/libraries/core/viewer/RendererWidget.cpp | 18 +- 2 files changed, 130 insertions(+), 112 deletions(-) diff --git a/sdk/libraries/core/viewer/InteractiveViewer.cpp b/sdk/libraries/core/viewer/InteractiveViewer.cpp index 544d6bb9..c886d3c0 100644 --- a/sdk/libraries/core/viewer/InteractiveViewer.cpp +++ b/sdk/libraries/core/viewer/InteractiveViewer.cpp @@ -130,27 +130,30 @@ InteractiveViewer* InteractiveViewer::getViewer(QString name) { QString letters[4] = {QString("R"), QString("L"), QString("A"), QString("P") }; singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters); singletonInstance->toggleOrientationDecorations(true); - singletonInstance->getRendererWidget()->getActiveCamera()->SetParallelProjection(1); + singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); } - else if (name == defaultNames[2]) { // Coronal Viewer - singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::LEFT_BACK); - QString letters[4] = {QString("R"), QString("L"), QString("S"), QString("I") }; - singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters); - singletonInstance->toggleOrientationDecorations(true); - singletonInstance->getRendererWidget()->getActiveCamera()->SetParallelProjection(1); - } - else if (name == defaultNames[3]) { // Sagittal Viewer - singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::BACK_DOWN); - QString letters[4] = {QString("A"), QString("P"), QString("S"), QString("I") }; - singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters); - singletonInstance->toggleOrientationDecorations(true); - singletonInstance->getRendererWidget()->getActiveCamera()->SetParallelProjection(1); - } - else if (name == defaultNames[4]) { // Arbitrary Viewer + else + if (name == defaultNames[2]) { // Coronal Viewer + singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::LEFT_BACK); + QString letters[4] = {QString("R"), QString("L"), QString("S"), QString("I") }; + singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters); + singletonInstance->toggleOrientationDecorations(true); + singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); + } + else + if (name == defaultNames[3]) { // Sagittal Viewer + singletonInstance->getRendererWidget()->setCameraOrientation(RendererWidget::BACK_DOWN); + QString letters[4] = {QString("A"), QString("P"), QString("S"), QString("I") }; + singletonInstance->getRendererWidget()->setOrientationDecorationsLetters(letters); + singletonInstance->toggleOrientationDecorations(true); + singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); + } + else + if (name == defaultNames[4]) { // Arbitrary Viewer // singletonInstance->getRendererWidget()->setCameraOrientation ( RendererWidget::RIGHT_DOWN ); - singletonInstance->toggleOrientationDecorations(false); -// singletonInstance->getRendererWidget()->getActiveCamera()->SetParallelProjection ( 1 ); - } + singletonInstance->toggleOrientationDecorations(false); +// singletonInstance->getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); + } return singletonInstance; @@ -760,39 +763,42 @@ QMenu* InteractiveViewer::getMenu() { // ---------------------- getToolBar ---------------------------- QToolBar* InteractiveViewer::getToolBar() { - if (frame && !viewerToolBar && myType == GEOMETRY_VIEWER) { - viewerToolBar = new QToolBar(objectName() + " ToolBar"); - // ensure object name is set for saving the state - viewerToolBar->setObjectName(objectName() + " ToolBar"); + if (frame && !viewerToolBar) { + if (myType == GEOMETRY_VIEWER) { + viewerToolBar = new QToolBar(objectName() + " ToolBar"); + // ensure object name is set for saving the state + viewerToolBar->setObjectName(objectName() + " ToolBar"); + + viewerToolBar->addAction(pickPointAction); + viewerToolBar->addAction(pickCellAction); + viewerToolBar->addAction(pickPointRegionAction); + viewerToolBar->addAction(pickCellRegionAction); + + viewerToolBar->addSeparator(); + + viewerToolBar->addAction(surfaceAction); + viewerToolBar->addAction(wireframeAction); + viewerToolBar->addAction(pointsAction); + if (colorAction) { + viewerToolBar->addAction(colorAction); + } + viewerToolBar->addAction(glyphAction); + viewerToolBar->addAction(toggleLabelAction); - viewerToolBar->addAction(pickPointAction); - viewerToolBar->addAction(pickCellAction); - viewerToolBar->addAction(pickPointRegionAction); - viewerToolBar->addAction(pickCellRegionAction); + viewerToolBar->addSeparator(); - viewerToolBar->addSeparator(); + viewerToolBar->addAction(toggleAxesAction); - viewerToolBar->addAction(surfaceAction); - viewerToolBar->addAction(wireframeAction); - viewerToolBar->addAction(pointsAction); - if (colorAction) { - viewerToolBar->addAction(colorAction); - } - viewerToolBar->addAction(glyphAction); - viewerToolBar->addAction(toggleLabelAction); + viewerToolBar->addAction(screenshotAction); - viewerToolBar->addSeparator(); + viewerToolBar->addSeparator(); - viewerToolBar->addAction(toggleAxesAction); - if (myType == SLICE_VIEWER) { + viewerToolBar->addAction(scalarDataColorAction); + } + /* if (myType == SLICE_VIEWER) { viewerToolBar->addAction(toggleOrientationDecorationsAction); } - viewerToolBar->addAction(screenshotAction); - - viewerToolBar->addSeparator(); - - viewerToolBar->addAction(scalarDataColorAction); - + */ } return viewerToolBar; @@ -1119,11 +1125,12 @@ void InteractiveViewer::keyPressEvent(QKeyEvent* e) { if (e->modifiers() == Qt::NoModifier && myType == GEOMETRY_VIEWER) { toggleLabelAction->toggle(); } - else if (e->modifiers() == Qt::AltModifier) { - // addWhatsThisItem("Alt+L", "Toggle light follows camera"); - rendererWidget->setLightFollowCamera(!rendererWidget->getLightFollowCamera()); - rendererWidget->refresh(); - } + else + if (e->modifiers() == Qt::AltModifier) { + // addWhatsThisItem("Alt+L", "Toggle light follows camera"); + rendererWidget->setLightFollowCamera(!rendererWidget->getLightFollowCamera()); + rendererWidget->refresh(); + } break; @@ -1164,10 +1171,11 @@ void InteractiveViewer::keyPressEvent(QKeyEvent* e) { refresh(this); } - else if (e->modifiers() == Qt::NoModifier) { - // addWhatsThisItem("S", "Take a screenshot"); - screenshot(); - } + else + if (e->modifiers() == Qt::NoModifier) { + // addWhatsThisItem("S", "Take a screenshot"); + screenshot(); + } break; @@ -1383,31 +1391,35 @@ void InteractiveViewer::keyPressEvent(QKeyEvent* e) { found = true; debugStream << "\t- Surface Actor" << endl; } - else if (c->getActor(InterfaceGeometry::Wireframe) == p) { - found = true; - debugStream << "\t- Wireframe Actor" << endl; - } - else if (c->getActor(InterfaceGeometry::Points) == p) { - found = true; - debugStream << "\t- Points Actor" << endl; - } + else + if (c->getActor(InterfaceGeometry::Wireframe) == p) { + found = true; + debugStream << "\t- Wireframe Actor" << endl; + } + else + if (c->getActor(InterfaceGeometry::Points) == p) { + found = true; + debugStream << "\t- Points Actor" << endl; + } break; case SLICE_VIEWER: if (c->getPixelActor() == p) { found = true; debugStream << "\t- Pixel Actor" << endl; } - else if (c->get2DImageActor() == p) { - found = true; - debugStream << "\t- 2D Image Actor" << endl; - } - else if (c->getPickPlaneActor() == p) { - found = true; - debugStream << "\t- Picked Plane Actor" << endl; - /* } else if (c->get2DAxesActor() == p) { - found = true; - debugStream << "\t- 2D Axes Actor" << endl; */ - } + else + if (c->get2DImageActor() == p) { + found = true; + debugStream << "\t- 2D Image Actor" << endl; + } + else + if (c->getPickPlaneActor() == p) { + found = true; + debugStream << "\t- Picked Plane Actor" << endl; + /* } else if (c->get2DAxesActor() == p) { + found = true; + debugStream << "\t- 2D Axes Actor" << endl; */ + } break; default: @@ -1957,20 +1969,21 @@ void InteractiveViewer::highlightModeChanged(QAction* selectedAction) { if (selectedAction == highlightSelectionAction) { propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), InteractiveViewer::SELECTION); } - else if (selectedAction == highlightSelectionOnlyAction) { - propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), InteractiveViewer::SELECTION_ONLY); - } else - - /* - if (selectedAction == highlightModeXtraHotAction) { - highlightMode = InteractiveViewer::XTRA_HOT; + if (selectedAction == highlightSelectionOnlyAction) { + propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), InteractiveViewer::SELECTION_ONLY); } else - */ - if (selectedAction == highlightOffAction) { - propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), InteractiveViewer::OFF); - } + + /* + if (selectedAction == highlightModeXtraHotAction) { + highlightMode = InteractiveViewer::XTRA_HOT; + } + else + */ + if (selectedAction == highlightOffAction) { + propertyObject->setProperty(highlightModeProperty->getName().toStdString().c_str(), InteractiveViewer::OFF); + } refresh(this); } @@ -1982,16 +1995,18 @@ void InteractiveViewer::cameraOrientationChanged(QAction* selectedAction) { resetCamera(); rendererWidget->refresh(); } - else if (selectedAction == cameraOrientationLeftUpAction) { - rendererWidget->setCameraOrientation(RendererWidget::LEFT_UP); - resetCamera(); - rendererWidget->refresh(); - } - else if (selectedAction == cameraOrientationRightUpAction) { - rendererWidget->setCameraOrientation(RendererWidget::RIGHT_UP); - resetCamera(); - rendererWidget->refresh(); - } + else + if (selectedAction == cameraOrientationLeftUpAction) { + rendererWidget->setCameraOrientation(RendererWidget::LEFT_UP); + resetCamera(); + rendererWidget->refresh(); + } + else + if (selectedAction == cameraOrientationRightUpAction) { + rendererWidget->setCameraOrientation(RendererWidget::RIGHT_UP); + resetCamera(); + rendererWidget->refresh(); + } QSettings& settings = Application::getSettings(); settings.beginGroup(Application::getName() + ".InteractiveViewer." + objectName().simplified().replace(" ", "")); @@ -2088,15 +2103,18 @@ void InteractiveViewer::pickingModeChanged(QAction* selectedAction) { if (selectedAction == pickCellAction) { initPicking(CELL_PICKING); } - else if (selectedAction == pickPointAction) { - initPicking(POINT_PICKING); - } - else if (selectedAction == pickCellRegionAction) { - initPicking(AREA_CELL_PICKING); - } - else if (selectedAction == pickPointRegionAction) { - initPicking(AREA_POINT_PICKING); - } + else + if (selectedAction == pickPointAction) { + initPicking(POINT_PICKING); + } + else + if (selectedAction == pickCellRegionAction) { + initPicking(AREA_CELL_PICKING); + } + else + if (selectedAction == pickPointRegionAction) { + initPicking(AREA_POINT_PICKING); + } } //-------------------- picked --------------------- diff --git a/sdk/libraries/core/viewer/RendererWidget.cpp b/sdk/libraries/core/viewer/RendererWidget.cpp index 25cdbe41..1f1ba75b 100644 --- a/sdk/libraries/core/viewer/RendererWidget.cpp +++ b/sdk/libraries/core/viewer/RendererWidget.cpp @@ -1399,16 +1399,16 @@ void RendererWidget::resetCameraSettings() { switch (cameraOrientation) { case LEFT_UP: // default position - cam->SetPosition(0, 0, -1); - cam->SetFocalPoint(0, 0, 0); - cam->SetViewUp(0, 1, 0); + cam->SetPosition(0.0, 0.0, -1.0); + cam->SetFocalPoint(0.0, 0.0, 0.0); + cam->SetViewUp(0.0, 1.0, 0.0); cam->OrthogonalizeViewUp(); break; case RIGHT_DOWN: // default position - cam->SetPosition(0, 0, -1); - cam->SetFocalPoint(0, 0, 0); - cam->SetViewUp(0, -1, 0); + cam->SetPosition(0.0, 0.0, -1.0); + cam->SetFocalPoint(0.0, 0.0, 0.0); + cam->SetViewUp(0.0, -1.0, 0.0); cam->OrthogonalizeViewUp(); break; // For Coronal view of Coronal Viewer @@ -1427,9 +1427,9 @@ void RendererWidget::resetCameraSettings() { break; case RIGHT_UP: default: - cam->SetPosition(0, 0, 1); - cam->SetFocalPoint(0, 0, 0); - cam->SetViewUp(0, 1, 0); + cam->SetPosition(0.0, 0.0, 1.0); + cam->SetFocalPoint(0.0, 0.0, 0.0); + cam->SetViewUp(0.0, 1.0, 0.0); cam->OrthogonalizeViewUp(); break; } -- GitLab From a684a1e7e6f7d19b3d4f65a464bf3b1a6b213ba9 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Thu, 31 Oct 2019 19:01:59 +0100 Subject: [PATCH 03/15] NEW tutorial to show how to change MainWindow central viewer This new action add a specific central viewer that display 2D images with the right orientation and no slider (BitmapViewer) BitmapViewer derived from InteractiveViewer. --- .../actions/switchviewer/BitmapViewer.cpp | 135 ++++++++++++++++++ tutorials/actions/switchviewer/BitmapViewer.h | 78 ++++++++++ tutorials/actions/switchviewer/CMakeLists.txt | 4 + .../actions/switchviewer/SwitchViewer.cpp | 59 ++++++++ tutorials/actions/switchviewer/SwitchViewer.h | 57 ++++++++ .../switchviewer/SwitchViewerExtension.cpp | 32 +++++ .../switchviewer/SwitchViewerExtension.h | 62 ++++++++ 7 files changed, 427 insertions(+) create mode 100644 tutorials/actions/switchviewer/BitmapViewer.cpp create mode 100644 tutorials/actions/switchviewer/BitmapViewer.h create mode 100644 tutorials/actions/switchviewer/CMakeLists.txt create mode 100644 tutorials/actions/switchviewer/SwitchViewer.cpp create mode 100644 tutorials/actions/switchviewer/SwitchViewer.h create mode 100644 tutorials/actions/switchviewer/SwitchViewerExtension.cpp create mode 100644 tutorials/actions/switchviewer/SwitchViewerExtension.h diff --git a/tutorials/actions/switchviewer/BitmapViewer.cpp b/tutorials/actions/switchviewer/BitmapViewer.cpp new file mode 100644 index 00000000..7cb6e39d --- /dev/null +++ b/tutorials/actions/switchviewer/BitmapViewer.cpp @@ -0,0 +1,135 @@ +/***************************************************************************** +* $CAMITK_LICENCE_BEGIN$ +* +* CamiTK - Computer Assisted Medical Intervention ToolKit +* (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) +* +* Visit http://camitk.imag.fr for more information +* +* This file is part of CamiTK. +* +* CamiTK is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* CamiTK is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with CamiTK. If not, see . +* +* $CAMITK_LICENCE_END$ +****************************************************************************/ + +#include "BitmapViewer.h" + +#include +#include +#include +#include + +#include + +#include + +using namespace camitk; + +// initialize static variables +QString BitmapViewer::BitmapViewerName = "2D Bitmap Viewer"; // required due to QString ref needed by InteractiveViewer cstr +BitmapViewer* BitmapViewer::singleton = nullptr; + +BitmapViewer* BitmapViewer::getInstance() { + if (!singleton) { + singleton = new BitmapViewer(); + } + + return singleton; +} + + +// -------------------- Constructor -------------------- +BitmapViewer::BitmapViewer() : InteractiveViewer(BitmapViewerName, InteractiveViewer::SLICE_VIEWER) { + // 2D images need x right, y up, z front + getRendererWidget()->setCameraOrientation(RendererWidget::RIGHT_UP); + // no decoration and grey background + getRendererWidget()->toggleOrientationDecorations(false); + getRendererWidget()->setGradientBackground(false); + getRendererWidget()->setBackgroundColor(0.8, 0.8, 0.8); + // parallel projection + getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); + + isVisible = false; + switchToolBar = nullptr; +} + +// -------------------- Destructor -------------------- +BitmapViewer::~BitmapViewer() { +} + +// -------------------- switchCentralViewer -------------------- +void BitmapViewer::switchCentralViewer() { + // if the central viewer is the medical image viewer switch to my2DBitmapViewer (if it is not switch back to the medical image viewer) + if (isVisible) { + // switch back to the default MedicalImageViewer + Application::getMainWindow()->setCentralViewer(MedicalImageViewer::getInstance()); + } + else { + // switch to the custom viewer + Application::getMainWindow()->setCentralViewer(BitmapViewer::getInstance()); + // force refresh + refresh(this); + } + + isVisible = !isVisible; +} + +// -------------------- refresh -------------------- +void BitmapViewer::refresh(Viewer* whoIsAsking) { + updateVisibility(); + InteractiveViewer::refresh(); +} + +// -------------------- getWidget -------------------- +QWidget* BitmapViewer::getWidget(QWidget* parent) { + QWidget* myWidget = InteractiveViewer::getWidget(parent); + // hide slice slider + sideFrame->hide(); + updateVisibility(); + return myWidget; +} + +// -------------------- getToolBar -------------------- +QToolBar* BitmapViewer::getToolBar() { + if (switchToolBar == nullptr) { + // create the action to switch between the default and this viewer + QAction* switchViewerAction = new QAction(tr("Bitmap Viewer"), this); + switchViewerAction->setCheckable(true); + switchViewerAction->setChecked(true); // first time getToolBar is called -> BitmapViewer is being displayed + switchViewerAction->setStatusTip(tr("Switch The Central Viewer")); + switchViewerAction->setWhatsThis(tr("Switch The Central Viewer between the BitmapViewer and MedicalImageViewer")); + connect(switchViewerAction, SIGNAL(toggled(bool)), this, SLOT(switchCentralViewer())); + + // create the toolbar and add the action to it + switchToolBar = new QToolBar(objectName() + " ToolBar"); + // ensure object name is set for saving the state + switchToolBar->setObjectName(objectName() + " ToolBar"); + + switchToolBar->addAction(switchViewerAction); + } + return switchToolBar; +} + +// -------------------- updateVisibility -------------------- +void BitmapViewer::updateVisibility() { + // as the default component does not know anything about my2DBitmapViewer, + // tell all the components that are already visible in the axial slices to be also + // visible in my2DBitmapViewer + for (Component* comp : Application::getAllComponents()) { + if (comp->getVisibility(InteractiveViewer::getAxialViewer())) { + comp->setVisibility(this, true); + } + } +} + diff --git a/tutorials/actions/switchviewer/BitmapViewer.h b/tutorials/actions/switchviewer/BitmapViewer.h new file mode 100644 index 00000000..4dd08b3c --- /dev/null +++ b/tutorials/actions/switchviewer/BitmapViewer.h @@ -0,0 +1,78 @@ +/***************************************************************************** +* $CAMITK_LICENCE_BEGIN$ +* +* CamiTK - Computer Assisted Medical Intervention ToolKit +* (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) +* +* Visit http://camitk.imag.fr for more information +* +* This file is part of CamiTK. +* +* CamiTK is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* CamiTK is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with CamiTK. If not, see . +* +* $CAMITK_LICENCE_END$ +****************************************************************************/ + + +#ifndef BITMAPVIEWER_H +#define BITMAPVIEWER_H + +#include + +class QToolBar; + +/** +* @brief +* InteractiveViewer specialized in 2D bitmap (images in jpeg, png...) +*/ +class BitmapViewer : public camitk::InteractiveViewer { + Q_OBJECT + +public: + + static BitmapViewer* getInstance(); + + virtual ~BitmapViewer() override; + + void refresh(camitk::Viewer* whoIsAsking = nullptr) override; + + QWidget* getWidget(QWidget* parent = nullptr) override; + + QToolBar* getToolBar() override; + +public slots: + + void switchCentralViewer(); + +protected: + + BitmapViewer(); + +private: + + static BitmapViewer* singleton; + + static QString BitmapViewerName; + + bool isVisible; + + QToolBar* switchToolBar; + + // set visibility of all possible component (that is component that can be displayed in 2D) + void updateVisibility(); + +}; + + +#endif // BITMAPVIEWER_H + diff --git a/tutorials/actions/switchviewer/CMakeLists.txt b/tutorials/actions/switchviewer/CMakeLists.txt new file mode 100644 index 00000000..40c3b436 --- /dev/null +++ b/tutorials/actions/switchviewer/CMakeLists.txt @@ -0,0 +1,4 @@ +camitk_extension(ACTION_EXTENSION + ENABLE_AUTO_TEST + #TEST_FILES bassin.msh brain.mha sinus.mhd +) diff --git a/tutorials/actions/switchviewer/SwitchViewer.cpp b/tutorials/actions/switchviewer/SwitchViewer.cpp new file mode 100644 index 00000000..0ae24fa9 --- /dev/null +++ b/tutorials/actions/switchviewer/SwitchViewer.cpp @@ -0,0 +1,59 @@ +/***************************************************************************** + * $CAMITK_LICENCE_BEGIN$ + * + * CamiTK - Computer Assisted Medical Intervention ToolKit + * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) + * + * Visit http://camitk.imag.fr for more information + * + * This file is part of CamiTK. + * + * CamiTK is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * CamiTK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with CamiTK. If not, see . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ + +#include "SwitchViewer.h" +#include +#include +#include +#include +#include + +#include + +using namespace camitk; + +// -------------------- SwitchViewer -------------------- +SwitchViewer::SwitchViewer(ActionExtension* extension) : Action(extension) { + setName("Switch Central Viewer"); + setEmbedded(false); // not embedded (and as the + setDescription("Tutorial action that switch the central viewer in/out. Trigger this action when no component is selected"); + setComponent(""); + + setFamily("Tutorial"); + addTag("Viewer"); + addTag("MainWindow"); +} + +// --------------- getWidget ------------------- +QWidget* SwitchViewer::getWidget() { + return nullptr; +} + +// --------------- apply ------------------- +Action::ApplyStatus SwitchViewer::apply() { + // just ask the BitMap viewer to switch the central viewer + BitmapViewer::getInstance()->switchCentralViewer(); + return SUCCESS; +} diff --git a/tutorials/actions/switchviewer/SwitchViewer.h b/tutorials/actions/switchviewer/SwitchViewer.h new file mode 100644 index 00000000..aa9519ad --- /dev/null +++ b/tutorials/actions/switchviewer/SwitchViewer.h @@ -0,0 +1,57 @@ +/***************************************************************************** + * $CAMITK_LICENCE_BEGIN$ + * + * CamiTK - Computer Assisted Medical Intervention ToolKit + * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) + * + * Visit http://camitk.imag.fr for more information + * + * This file is part of CamiTK. + * + * CamiTK is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * CamiTK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with CamiTK. If not, see . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ + +#ifndef SWITCH_VIEWER_H +#define SWITCH_VIEWER_H + +#include + +namespace camitk { +class InteractiveViewer; +class Viewer; +} + +/** + * Demonstrates how to switch the central image viewer. + */ +class SwitchViewer : public camitk::Action { + +public: + /// the constructor + SwitchViewer(camitk::ActionExtension*); + + /// the destructor + virtual ~SwitchViewer() = default; + + /// method called when the action when the action is triggered (i.e. started) + virtual QWidget* getWidget(); + +public slots: + /// method called when the action is applied + virtual ApplyStatus apply(); + +}; + +#endif // SWITCH_VIEWER_H diff --git a/tutorials/actions/switchviewer/SwitchViewerExtension.cpp b/tutorials/actions/switchviewer/SwitchViewerExtension.cpp new file mode 100644 index 00000000..cb40f43c --- /dev/null +++ b/tutorials/actions/switchviewer/SwitchViewerExtension.cpp @@ -0,0 +1,32 @@ +/***************************************************************************** + * $CAMITK_LICENCE_BEGIN$ + * + * CamiTK - Computer Assisted Medical Intervention ToolKit + * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) + * + * Visit http://camitk.imag.fr for more information + * + * This file is part of CamiTK. + * + * CamiTK is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * CamiTK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with CamiTK. If not, see . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ +#include "SwitchViewerExtension.h" +#include "SwitchViewer.h" + +// -------------------- init -------------------- +void SwitchViewerExtension::init() { + registerNewAction(SwitchViewer); +} + diff --git a/tutorials/actions/switchviewer/SwitchViewerExtension.h b/tutorials/actions/switchviewer/SwitchViewerExtension.h new file mode 100644 index 00000000..042266d7 --- /dev/null +++ b/tutorials/actions/switchviewer/SwitchViewerExtension.h @@ -0,0 +1,62 @@ +/***************************************************************************** + * $CAMITK_LICENCE_BEGIN$ + * + * CamiTK - Computer Assisted Medical Intervention ToolKit + * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO) + * + * Visit http://camitk.imag.fr for more information + * + * This file is part of CamiTK. + * + * CamiTK is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * CamiTK is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with CamiTK. If not, see . + * + * $CAMITK_LICENCE_END$ + ****************************************************************************/ + + +#ifndef SWITCH_VIEWER_EXTENSION_H +#define SWITCH_VIEWER_EXTENSION_H + +#include +#include +#include + +/// shows how to switch the central viewer in and out +class SwitchViewerExtension : public camitk::ActionExtension { + Q_OBJECT + Q_INTERFACES(camitk::ActionExtension) + Q_PLUGIN_METADATA(IID "fr.imag.camitk.tutorials.action.switchviewer") + +public: + /// the constructor + SwitchViewerExtension() : ActionExtension() {}; + + /// the destructor + virtual ~SwitchViewerExtension() = default; + + /// initialize all the actions + virtual void init(); + + /// Method that return the action extension name + virtual QString getName() { + return "Switch Viewer"; + }; + + /// Method that return the action extension descrption + virtual QString getDescription() { + return "This extension contains a simple medical image viewer (axial slice) and a simple action to switch the central viewer (by default, the medical image viewer) to and from the simple medical image viewer."; + }; + +}; + +#endif // BASIC_PICKING_EXTENSION_H -- GitLab From aa288e87e3f4cb674cb73f6d3a314b794d1a7cb3 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Sun, 3 Nov 2019 15:02:55 +0100 Subject: [PATCH 04/15] FIXED clean CMakeLists: no possible autotest on viewer --- tutorials/actions/switchviewer/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/tutorials/actions/switchviewer/CMakeLists.txt b/tutorials/actions/switchviewer/CMakeLists.txt index 40c3b436..df9370bb 100644 --- a/tutorials/actions/switchviewer/CMakeLists.txt +++ b/tutorials/actions/switchviewer/CMakeLists.txt @@ -1,4 +1,2 @@ camitk_extension(ACTION_EXTENSION - ENABLE_AUTO_TEST - #TEST_FILES bassin.msh brain.mha sinus.mhd ) -- GitLab From 78d673418cddc7b0cc784e0ecaeb9e4906138b1e Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 17:43:04 +0100 Subject: [PATCH 05/15] NEW improved viewers and toolbar management The MainWindow API is more clearly define. The distinction between docked and central viewer is better, and now follow the same logic. The viewer manages its own toolbar visibility while the MainWindow manages the toolbar widget. --- sdk/applications/imp/ImpMainWindow.cpp | 69 +++++++++++----- sdk/libraries/core/application/MainWindow.cpp | 78 ++++++++++++------- sdk/libraries/core/application/MainWindow.h | 44 ++++++++--- .../core/viewer/MedicalImageViewer.cpp | 32 +++----- sdk/libraries/core/viewer/Viewer.cpp | 10 +++ sdk/libraries/core/viewer/Viewer.h | 11 +++ 6 files changed, 170 insertions(+), 74 deletions(-) diff --git a/sdk/applications/imp/ImpMainWindow.cpp b/sdk/applications/imp/ImpMainWindow.cpp index e48154e8..862b1b6f 100644 --- a/sdk/applications/imp/ImpMainWindow.cpp +++ b/sdk/applications/imp/ImpMainWindow.cpp @@ -85,7 +85,7 @@ ImpMainWindow::ImpMainWindow() : MainWindow("imp") { dockWidgetExplorer->raise(); } - showViewer(ActionViewer::getInstance(), false); + showDockViewer(ActionViewer::getInstance(), false); ActionViewer::getInstance()->setSearchPanelVisible(true); showStatusBar(true); } @@ -292,9 +292,9 @@ void ImpMainWindow::initMenuBar() { //--------------------------initToolBar------------------------------- void ImpMainWindow::initToolBar() { - mainToolbar = addToolBar("Main toolbar"); + mainToolbar = addToolBar("Main Toolbar"); // ensure object name is set for saving the state - mainToolbar->setObjectName("imp main toolbar"); + mainToolbar->setObjectName("ImpMainWindow Main Toolbar"); mainToolbar->addAction(fileOpen); mainToolbar->addAction(fileSave); mainToolbar->addAction(QWhatsThis::createAction(this)); @@ -387,21 +387,24 @@ void ImpMainWindow::resetWindows() { addDockWidget(Qt::LeftDockWidgetArea, it.value()); it.value()->show(); } - else if (it.value()->widget() == FrameExplorer::getInstance()->getWidget(NULL)) { - removeDockWidget(it.value()); - addDockWidget(Qt::LeftDockWidgetArea, it.value()); - it.value()->show(); - } - else if (it.value()->widget() == PropertyExplorer::getInstance()->getWidget()) { - removeDockWidget(it.value()); - addDockWidget(Qt::LeftDockWidgetArea, it.value()); - it.value()->show(); - } - else if (it.value()->widget() == ActionViewer::getInstance()->getWidget()) { - removeDockWidget(it.value()); - addDockWidget(Qt::RightDockWidgetArea, it.value()); - it.value()->show(); - } + else + if (it.value()->widget() == FrameExplorer::getInstance()->getWidget(NULL)) { + removeDockWidget(it.value()); + addDockWidget(Qt::LeftDockWidgetArea, it.value()); + it.value()->show(); + } + else + if (it.value()->widget() == PropertyExplorer::getInstance()->getWidget()) { + removeDockWidget(it.value()); + addDockWidget(Qt::LeftDockWidgetArea, it.value()); + it.value()->show(); + } + else + if (it.value()->widget() == ActionViewer::getInstance()->getWidget()) { + removeDockWidget(it.value()); + addDockWidget(Qt::RightDockWidgetArea, it.value()); + it.value()->show(); + } } //Merge Explorer and FrameExplorer viewers in one layout QDockWidget* dockWidgetExplorer = dockWidgetMap.value(Explorer::getInstance(), NULL); @@ -489,6 +492,36 @@ void ImpMainWindow::updateViewMenu() { } } + // change the central viewer if there is more than one viewer in the central area + if (qobject_cast(centralWidget())->count() > 1) { + viewMenu->addSeparator()->setText(tr("Toggle Central Viewers")); + for(Viewer *v : viewers) { + int i = 0; + // beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() + // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) + // in order not to modify the central widget parenting + while (i(centralWidget())->count() && qobject_cast(centralWidget())->widget(i)!=v->getWidget(centralWidget())) + i++; + if (i(centralWidget())->count()) { + viewMenu->addAction(v->objectName()); + } + } + +// // add a toggle action +// for (int i = 0; i < qobject_cast(centralWidget())->count(); i++) { +// QWidget* cWidget = qobject_cast(centralWidget())->widget(i); +// // get the viewer associated with the widget in the central area +// // beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() +// // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) +// // in order not to modify the central widget parenting +// auto it = std::find_if(viewers.begin(), viewers.end(), [cWidget,centralWidget=centralWidget()](Viewer * v) { +// return v->getWidget(centralWidget) == cWidget; +// }); +// Viewer* cViewer = (*it); +// viewMenu->addAction(cViewer->objectName()); +// } + } + // insert viewers on/off actions viewMenu->addSeparator()->setText(tr("Toggle Viewers")); viewMenu->addAction(viewResetWindows); diff --git a/sdk/libraries/core/application/MainWindow.cpp b/sdk/libraries/core/application/MainWindow.cpp index 8b984b1d..be88de14 100644 --- a/sdk/libraries/core/application/MainWindow.cpp +++ b/sdk/libraries/core/application/MainWindow.cpp @@ -187,15 +187,10 @@ void MainWindow::setWindowSubtitle(QString subtitle) { bool MainWindow::addViewer(Viewer* theViewer) { if (!viewers.contains(theViewer)) { viewers.append(theViewer); + // connect connect(theViewer, SIGNAL(selectionChanged()), this, SLOT(refresh())); - // add the toolbar - if (theViewer->getToolBar()) { - QToolBar* viewerToolBar = theViewer->getToolBar(); - addToolBar(viewerToolBar); - } - return true; } @@ -207,10 +202,33 @@ bool MainWindow::removeViewer(Viewer* viewer) { return true; } +// ------------- showDockViewer ----------------- +void MainWindow::showDockViewer(Viewer* theViewer, bool visible) { + if (dockWidgetMap.contains(theViewer)) { + // set visibility of the viewer + dockWidgetMap[theViewer]->setVisible(visible); + // set visibility of the toolbar + showViewerToolbar(theViewer, visible); + } +} + // ------------- showViewer ----------------- void MainWindow::showViewer(Viewer* theViewer, bool visible) { - if (viewers.contains(theViewer)) { - dockWidgetMap[theViewer]->setVisible(visible); + showDockViewer(theViewer, visible); +} + +// ------------- showViewerToolbar ----------------- +void MainWindow::showViewerToolbar(Viewer* theViewer, bool visible) { + QToolBar* viewerToolBar = theViewer->getToolBar(); + if (viewerToolBar != nullptr) { + if (visible && theViewer->getToolBarVisibility()) { + addToolBar(viewerToolBar); + viewerToolBar->setVisible(true); + } + else { + removeToolBar(viewerToolBar); + viewerToolBar->setVisible(false); + } } } @@ -219,49 +237,56 @@ void MainWindow::refreshViewers() { foreach (Viewer* v, viewers) { v->refresh(); } + // update the central viewer toolbar visibility + showViewerToolbar(centralViewer, true); } // ------------- addDockViewer ----------------- void MainWindow::addDockViewer(Qt::DockWidgetArea dockingArea, Viewer* theViewer) { if (addViewer(theViewer)) { - // create the dock widget and insert it - QDockWidget* viewerDock = new QDockWidget(theViewer->objectName(), this); - viewerDock->setObjectName(theViewer->objectName()); - QWidget* viewerWidget = theViewer->getWidget(viewerDock); - + // create the dock widget and insert it only if the viewer has a widget + QWidget* viewerWidget = theViewer->getWidget(this); if (viewerWidget) { + // add the widget + QDockWidget* viewerDock = new QDockWidget(theViewer->objectName(), this); + viewerDock->setObjectName(theViewer->objectName()); viewerDock->setWidget(viewerWidget); addDockWidget(dockingArea, viewerDock); - // update map + + // update the map dockWidgetMap.insert(theViewer, viewerDock); } - else { - delete viewerDock; - } - } - else { - dockWidgetMap.value(theViewer)->show(); + } + // show the viewer anyway + showDockViewer(theViewer, true); } // ------------- setCentralViewer ----------------- void MainWindow::setCentralViewer(Viewer* theViewer) { // get the viewer widget (must have something to show as it is a viewer after all!) - QWidget *viewerWidget = theViewer->getWidget(this); + QWidget* viewerWidget = theViewer->getWidget(this); if (viewerWidget != nullptr) { // add the viewer to the list (if not already in the list) addViewer(theViewer); - // if needed, create the default (empty) central widget inside which the central viewers can be added - if (centralWidget()==0) { - setCentralWidget(new QStackedWidget(this)); + // if needed, create the default (empty) central widget inside which the central viewers can be added + if (centralWidget() == 0) { + setCentralWidget(new QStackedWidget(this)); + } + else { + // there is already a central viewer, just hide its toolbar + showViewerToolbar(centralViewer, false); } - // add the widget to the central widget + // add the viewer's widget qobject_cast(centralWidget())->addWidget(viewerWidget); qobject_cast(centralWidget())->setCurrentWidget(viewerWidget); centralViewer = theViewer; + + // show its toolbar + showViewerToolbar(centralViewer, true); } } @@ -278,6 +303,8 @@ void MainWindow::refresh() { v->refresh(); } } + // update the central viewer toolbar visibility + showViewerToolbar(centralViewer, true); } // ------------- showStatusBar ----------------- @@ -290,7 +317,6 @@ QProgressBar* MainWindow::getProgressBar() { return myProgressBar; } - // ------------- setApplicationConsole ----------------- void MainWindow::redirectToConsole(bool visible) { if (visible) { diff --git a/sdk/libraries/core/application/MainWindow.h b/sdk/libraries/core/application/MainWindow.h index 60a172e6..ae70e888 100644 --- a/sdk/libraries/core/application/MainWindow.h +++ b/sdk/libraries/core/application/MainWindow.h @@ -124,12 +124,28 @@ public: /// @name Viewers ///@{ + ///@cond + /** + * TODO CAMITK_DEPRECATED. This section list all the methods marked as deprecated. They are to be removed in CamiTK 5.0 + * @deprecated + * + * DEPRECATED (CamiTK 5.0) -> to be removed + * This method is now called showDockViewer. + */ /// set the visibility for the given viewer (if it is in a dock) virtual void showViewer(Viewer*, bool); + ///@endcond + /// set the visibility for the given docked viewer and its toolbar + virtual void showDockViewer(Viewer*, bool); + /** add a Viewer to the application as a docking widget and specify where it has to be docked * Note that MainWindow takes ownership of the Viewer pointer and deletes it at the appropriate time. + * * This method calls addViewer(...). + * This method calls showDockViewer(..,true) and therefore showViewerToolbar(..,true) + * + * \note MainWindow takes ownership of the viewer pointer and deletes it when it is itself destroyed. */ virtual void addDockViewer(Qt::DockWidgetArea, Viewer*); @@ -137,16 +153,26 @@ public: void refreshViewers(); /** set the central Viewer of the application. - * Note that MainWindow takes ownership of the Viewer pointer and deletes it at the appropriate time. - * This method calls addViewer(...). + * The central viewer has a specific behaviour in a MainWindow. It uses a QStackWidget to keep + * all the central viewer that are used. When a new central viewers is set, the previous central + * viewer (i.e., its widget) is hidden but not destroyed. + * + * This method calls addViewer(..). + * This method calls showViewerToolbar(..,true) + * + * \note MainWindow takes ownership of the viewer pointer and deletes it when it is itself destroyed. */ virtual void setCentralViewer(Viewer*); /** - * @Return the actual central viewer. - * @return + * @return the current central viewer. */ virtual const Viewer& getCentralViewer() const; + + /** Set the visibility of a viewer's toolbar. + * This method respect the toolbar visibility property of the viewer. + */ + virtual void showViewerToolbar(Viewer* theViewer, bool visible); ///@} public slots: @@ -194,9 +220,10 @@ protected: /** * TODO CAMITK_DEPRECATED. This section list all the methods marked as deprecated. They are to be removed in CamiTK 5.0 * @deprecated + * + * DEPRECATED (CamiTK 5.0) -> to be removed * Removing viewers can be harmful. Central viewer is now simply hidden, therefore there is no need to remove it. * It will keep itself refreshed and when shown again will be up to date. - * DEPRECATED (CamiTK 5.0) -> to be removed * * @brief Remove the given viewer from the list of viewer. * @note This tell all Component not to be visible anymore in this viewer instance, remove it from the list of viewers and delete it. @@ -217,12 +244,11 @@ private: /** * Add a viewer (called by addDockViewer and setCentralViewer), returns true if not already added. - * Note that MainWindow takes ownership of the Viewer pointer and deletes it at the appropriate time. - * This method connects the selectionChanged signal of the viewer to the refresh method. - * Before CamiTK 4.x this method was a public method. + * Note that MainWindow takes ownership of the Viewer pointer and deletes it when it is itself destroyed. + * + * This method connects the selectionChanged signal of the viewer to the refresh method of MainWindow. */ virtual bool addViewer(Viewer*); - ///@endcond /// the output stream for the application console ConsoleStream cout; diff --git a/sdk/libraries/core/viewer/MedicalImageViewer.cpp b/sdk/libraries/core/viewer/MedicalImageViewer.cpp index 2b776870..42a9fe1e 100644 --- a/sdk/libraries/core/viewer/MedicalImageViewer.cpp +++ b/sdk/libraries/core/viewer/MedicalImageViewer.cpp @@ -135,25 +135,13 @@ QWidget* MedicalImageViewer::getWidget(QWidget* parent) { viewers.insert(VIEWER_CORONAL, InteractiveViewer::getCoronalViewer()); viewers.insert(VIEWER_SAGITTAL, InteractiveViewer::getSagittalViewer()); - //-- add the InteractiveViewers -// topLeftLayout = new QVBoxLayout(); -// frameLayout->addLayout(topLeftLayout, 0, 0); -// topLeftLayout->addWidget(InteractiveViewer::getAxialViewer()->getWidget(frame)); // north-west -// topLeftLayout->addWidget(InteractiveViewer::getArbitraryViewer()->getWidget(frame)); // north-west -// frameLayout->addWidget(InteractiveViewer::getCoronalViewer()->getWidget(frame), 0, 1); // north-east -// frameLayout->addWidget(InteractiveViewer::getSagittalViewer()->getWidget(frame), 1, 0); // south-west -// frameLayout->addWidget(InteractiveViewer::get3DViewer()->getWidget(frame), 1, 1); // south-east - topLeftLayout = new QVBoxLayout(); frameLayout->addLayout(topLeftLayout, 0, 0); - topLeftLayout->addWidget(InteractiveViewer::getAxialViewer()->getWidget(frame)); -// frameLayout->addWidget(InteractiveViewer::getAxialViewer()->getWidget(frame), 0, 0); // north-west + topLeftLayout->addWidget(InteractiveViewer::getAxialViewer()->getWidget(frame)); // equivalent of addWidget(InteractiveViewer::getAxialViewer()->getWidget(frame), 0, 0) = north-west frameLayout->addWidget(InteractiveViewer::getCoronalViewer()->getWidget(frame), 1, 0); // north-east frameLayout->addWidget(InteractiveViewer::getSagittalViewer()->getWidget(frame), 1, 1); // south-west frameLayout->addWidget(InteractiveViewer::get3DViewer()->getWidget(frame), 0, 1); // south-east - - //-- connect foreach (LayoutVisibility v, viewerVisibility) { if (viewers.value(v)) { // prevent ALL @@ -247,8 +235,13 @@ void MedicalImageViewer::updateLayout() { viewers.value(visibleLayout)->getWidget(frame)->show(); } - if (autoUpdateToolbarVisibility && (visibleLayout == VIEWER_3D || visibleLayout == VIEWER_ALL)) { - getToolBar()->show(); + if (autoUpdateToolbarVisibility) { + if (visibleLayout == VIEWER_3D || visibleLayout == VIEWER_ALL) { + setToolBarVisibility(true); + } + else { + setToolBarVisibility(false); + } } } @@ -268,12 +261,9 @@ void MedicalImageViewer::synchronizeSelection() { } // -------------------- setToolbarAutoVisibility -------------------- -void MedicalImageViewer::setToolbarAutoVisibility(bool toolbarVisibility) { - autoUpdateToolbarVisibility = toolbarVisibility; - getToolBar()->setVisible(autoUpdateToolbarVisibility); - if (!autoUpdateToolbarVisibility) { - getToolBar()->close(); - } +void MedicalImageViewer::setToolbarAutoVisibility(bool toolbarAutoVisibility) { + autoUpdateToolbarVisibility = toolbarAutoVisibility; + setToolBarVisibility(false); } } diff --git a/sdk/libraries/core/viewer/Viewer.cpp b/sdk/libraries/core/viewer/Viewer.cpp index ef44e0f0..6f8714df 100644 --- a/sdk/libraries/core/viewer/Viewer.cpp +++ b/sdk/libraries/core/viewer/Viewer.cpp @@ -32,6 +32,7 @@ namespace camitk { //---------------------- constructor ------------------------ Viewer::Viewer(QString name): QObject() { setObjectName(name); + toolbarVisibility = true; } //---------------------- selectionChanged ------------------------ @@ -54,5 +55,14 @@ void Viewer::clearSelection() { emit selectionChanged(); } +//---------------------- setToolBarVisibility ------------------------ +void Viewer::setToolBarVisibility(bool toolbarVisibility) { + this->toolbarVisibility = toolbarVisibility; +} + +//---------------------- getToolBarVisibility ------------------------ +bool Viewer::getToolBarVisibility() { + return toolbarVisibility; +} } diff --git a/sdk/libraries/core/viewer/Viewer.h b/sdk/libraries/core/viewer/Viewer.h index 9d68720e..d32c10f7 100644 --- a/sdk/libraries/core/viewer/Viewer.h +++ b/sdk/libraries/core/viewer/Viewer.h @@ -86,6 +86,14 @@ public: return nullptr; }; + /** set the visibility of the toolbar in the main window (true by default). + * If the visibility is set to false, the next call to setCentralViewer(..) or addDockViwer(...) will remove it + */ + void setToolBarVisibility(bool); + + /// get the current value of the toolbar visibility + bool getToolBarVisibility(); + /// Update the whole tree of the representation of the Component. /// Is actually useful (and defined) in Explorer. virtual void refreshInterfaceNode(Component* comp) {}; @@ -109,6 +117,9 @@ protected: /// clear the selection void clearSelection(); +private: + /// the current toolbar visibility + bool toolbarVisibility; }; } -- GitLab From 8d865a0746d97d9ab6823cf6bbe60d2f2dbb6163 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 17:44:01 +0100 Subject: [PATCH 06/15] FIXED code cleaning --- .../core/component/mesh/MeshComponent.cpp | 24 ++++---- .../core/viewer/InteractiveViewer.cpp | 57 +++++++++---------- sdk/libraries/core/viewer/InteractiveViewer.h | 2 +- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/sdk/libraries/core/component/mesh/MeshComponent.cpp b/sdk/libraries/core/component/mesh/MeshComponent.cpp index e696f79e..9377deb0 100644 --- a/sdk/libraries/core/component/mesh/MeshComponent.cpp +++ b/sdk/libraries/core/component/mesh/MeshComponent.cpp @@ -145,13 +145,13 @@ void MeshComponent::init() { // build the selection widget auto* hbox = new QVBoxLayout(selectionWidget); - auto* selectionToolBar = new QToolBar(selectionWidget); - selectionToolBar->addAction(removeSelections); - selectionToolBar->addAction(mergeSelection); - selectionToolBar->addAction(inspectSelection); - selectionToolBar->addWidget(insertionPolicyBox); + auto* selectionToolbar = new QToolBar(selectionWidget); + selectionToolbar->addAction(removeSelections); + selectionToolbar->addAction(mergeSelection); + selectionToolbar->addAction(inspectSelection); + selectionToolbar->addWidget(insertionPolicyBox); hbox->addWidget(selectionView); - hbox->addWidget(selectionToolBar); + hbox->addWidget(selectionToolbar); selectionWidget->setLayout(hbox); // data widget @@ -200,13 +200,13 @@ void MeshComponent::init() { // build the data widget auto* dataBox = new QVBoxLayout(dataWidget); - auto* dataToolBar = new QToolBar(dataWidget); - dataToolBar->addAction(removeData); - dataToolBar->addAction(inspectData); - dataToolBar->addWidget(displayTypePolicyBox); - dataToolBar->addWidget(vectorRepresentationPolicyBox); + auto* dataToolbar = new QToolBar(dataWidget); + dataToolbar->addAction(removeData); + dataToolbar->addAction(inspectData); + dataToolbar->addWidget(displayTypePolicyBox); + dataToolbar->addWidget(vectorRepresentationPolicyBox); dataBox->addWidget(dataView); - dataBox->addWidget(dataToolBar); + dataBox->addWidget(dataToolbar); dataWidget->setLayout(dataBox); } diff --git a/sdk/libraries/core/viewer/InteractiveViewer.cpp b/sdk/libraries/core/viewer/InteractiveViewer.cpp index c886d3c0..dc7ce7b0 100644 --- a/sdk/libraries/core/viewer/InteractiveViewer.cpp +++ b/sdk/libraries/core/viewer/InteractiveViewer.cpp @@ -206,7 +206,7 @@ InteractiveViewer::InteractiveViewer(QString& name, ViewerType type) : Viewer(na //-- create the slice slider if needed viewerMenu = nullptr; - viewerToolBar = nullptr; + viewerToolbar = nullptr; screenshotActionMenu = nullptr; displayedTopLevelComponents = 0; @@ -214,14 +214,12 @@ InteractiveViewer::InteractiveViewer(QString& name, ViewerType type) : Viewer(na pickingEffectIsSelecting = true; // default effect isPicking = false; // by default, viewer is not picking - if (myType == SLICE_VIEWER) + if (myType == SLICE_VIEWER) { // by default, the 2D scenes are set to pick slice pixels - { initPicking(InteractiveViewer::PIXEL_PICKING); } - else + else { // no picking - { initPicking(InteractiveViewer::NO_PICKING); } @@ -246,8 +244,8 @@ InteractiveViewer::~InteractiveViewer() { delete viewerMenu; viewerMenu = nullptr; - delete viewerToolBar; - viewerToolBar = nullptr; + delete viewerToolbar; + viewerToolbar = nullptr; delete frame; frame = nullptr; @@ -474,9 +472,7 @@ QWidget* InteractiveViewer::getWidget(QWidget* parent) { else { if (frame->parentWidget() != parent) { bool isVisible = frame->isVisible(); - //frame->parentWidget()->layout()->removeWidget(frame); frame->setParent(parent); - //parent->layout()->addWidget(frame); frame->setVisible(isVisible); } } @@ -763,37 +759,36 @@ QMenu* InteractiveViewer::getMenu() { // ---------------------- getToolBar ---------------------------- QToolBar* InteractiveViewer::getToolBar() { - if (frame && !viewerToolBar) { + if (frame && !viewerToolbar) { if (myType == GEOMETRY_VIEWER) { - viewerToolBar = new QToolBar(objectName() + " ToolBar"); + viewerToolbar = new QToolBar(objectName() + " Toolbar"); // ensure object name is set for saving the state - viewerToolBar->setObjectName(objectName() + " ToolBar"); + viewerToolbar->setObjectName(objectName() + " Toolbar"); - viewerToolBar->addAction(pickPointAction); - viewerToolBar->addAction(pickCellAction); - viewerToolBar->addAction(pickPointRegionAction); - viewerToolBar->addAction(pickCellRegionAction); + viewerToolbar->addAction(pickPointAction); + viewerToolbar->addAction(pickCellAction); + viewerToolbar->addAction(pickPointRegionAction); + viewerToolbar->addAction(pickCellRegionAction); - viewerToolBar->addSeparator(); + viewerToolbar->addSeparator(); - viewerToolBar->addAction(surfaceAction); - viewerToolBar->addAction(wireframeAction); - viewerToolBar->addAction(pointsAction); + viewerToolbar->addAction(surfaceAction); + viewerToolbar->addAction(wireframeAction); + viewerToolbar->addAction(pointsAction); if (colorAction) { - viewerToolBar->addAction(colorAction); + viewerToolbar->addAction(colorAction); } - viewerToolBar->addAction(glyphAction); - viewerToolBar->addAction(toggleLabelAction); - - viewerToolBar->addSeparator(); + viewerToolbar->addAction(glyphAction); + viewerToolbar->addAction(toggleLabelAction); - viewerToolBar->addAction(toggleAxesAction); + viewerToolbar->addSeparator(); - viewerToolBar->addAction(screenshotAction); + viewerToolbar->addAction(toggleAxesAction); + viewerToolbar->addAction(screenshotAction); - viewerToolBar->addSeparator(); + viewerToolbar->addSeparator(); - viewerToolBar->addAction(scalarDataColorAction); + viewerToolbar->addAction(scalarDataColorAction); } /* if (myType == SLICE_VIEWER) { viewerToolBar->addAction(toggleOrientationDecorationsAction); @@ -801,7 +796,7 @@ QToolBar* InteractiveViewer::getToolBar() { */ } - return viewerToolBar; + return viewerToolbar; } // ---------------------- initActions ---------------------------- @@ -854,7 +849,7 @@ void InteractiveViewer::initActions() { scalarDataModel = new MeshDataFilterModel(MeshComponent::POINTS | MeshComponent::CELLS, MeshComponent::SCALARS, this); // combo box for viewing the scalar data model - scalarDataComboBox = new QComboBox(viewerToolBar); + scalarDataComboBox = new QComboBox(viewerToolbar); scalarDataComboBox->setModel(scalarDataModel); scalarDataComboBox->setMinimumWidth(150); diff --git a/sdk/libraries/core/viewer/InteractiveViewer.h b/sdk/libraries/core/viewer/InteractiveViewer.h index c9a041da..a0547d17 100644 --- a/sdk/libraries/core/viewer/InteractiveViewer.h +++ b/sdk/libraries/core/viewer/InteractiveViewer.h @@ -436,7 +436,7 @@ protected: QMenu* viewerMenu; /// the QToolBar for the InteractiveViewer - QToolBar* viewerToolBar; + QToolBar* viewerToolbar; /// the ComboBox for mesh scalar data QComboBox* scalarDataComboBox; -- GitLab From 7aa67ed6235238181cc2f445c2754d046d666027 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 17:45:26 +0100 Subject: [PATCH 07/15] FIXED added required update of the application Since the toolbar visibility is now manages inside the viewer, the application needs to be refreshed when the MedicalImageViewer visible viewers are changed --- sdk/actions/application/Show3DViewer.cpp | 1 + sdk/actions/application/ShowAllViewers.cpp | 1 + sdk/actions/application/ShowArbitraryViewer.cpp | 1 + sdk/actions/application/ShowAxialViewer.cpp | 1 + sdk/actions/application/ShowCoronalViewer.cpp | 1 + sdk/actions/application/ShowSagittalViewer.cpp | 1 + 6 files changed, 6 insertions(+) diff --git a/sdk/actions/application/Show3DViewer.cpp b/sdk/actions/application/Show3DViewer.cpp index fff2e5a5..d091c88b 100644 --- a/sdk/actions/application/Show3DViewer.cpp +++ b/sdk/actions/application/Show3DViewer.cpp @@ -61,5 +61,6 @@ QWidget* Show3DViewer::getWidget() { // --------------- apply ------------------- Action::ApplyStatus Show3DViewer::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_3D); + Application::refresh(); return SUCCESS; } diff --git a/sdk/actions/application/ShowAllViewers.cpp b/sdk/actions/application/ShowAllViewers.cpp index 4d60fa49..7b687a2e 100644 --- a/sdk/actions/application/ShowAllViewers.cpp +++ b/sdk/actions/application/ShowAllViewers.cpp @@ -61,5 +61,6 @@ QWidget* ShowAllViewers::getWidget() { // --------------- apply ------------------- Action::ApplyStatus ShowAllViewers::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_ALL); + Application::refresh(); return SUCCESS; } diff --git a/sdk/actions/application/ShowArbitraryViewer.cpp b/sdk/actions/application/ShowArbitraryViewer.cpp index 6365450a..39094316 100644 --- a/sdk/actions/application/ShowArbitraryViewer.cpp +++ b/sdk/actions/application/ShowArbitraryViewer.cpp @@ -61,5 +61,6 @@ QWidget* ShowArbitraryViewer::getWidget() { // --------------- apply ------------------- Action::ApplyStatus ShowArbitraryViewer::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_ARBITRARY); + Application::refresh(); return SUCCESS; } diff --git a/sdk/actions/application/ShowAxialViewer.cpp b/sdk/actions/application/ShowAxialViewer.cpp index 7046fb74..c9ddb37c 100644 --- a/sdk/actions/application/ShowAxialViewer.cpp +++ b/sdk/actions/application/ShowAxialViewer.cpp @@ -61,5 +61,6 @@ QWidget* ShowAxialViewer::getWidget() { // --------------- apply ------------------- Action::ApplyStatus ShowAxialViewer::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_AXIAL); + Application::refresh(); return SUCCESS; } diff --git a/sdk/actions/application/ShowCoronalViewer.cpp b/sdk/actions/application/ShowCoronalViewer.cpp index 1ca2c8ac..19beb6fc 100644 --- a/sdk/actions/application/ShowCoronalViewer.cpp +++ b/sdk/actions/application/ShowCoronalViewer.cpp @@ -61,5 +61,6 @@ QWidget* ShowCoronalViewer::getWidget() { // --------------- apply ------------------- Action::ApplyStatus ShowCoronalViewer::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_CORONAL); + Application::refresh(); return SUCCESS; } diff --git a/sdk/actions/application/ShowSagittalViewer.cpp b/sdk/actions/application/ShowSagittalViewer.cpp index d0342ba7..6ec9e733 100644 --- a/sdk/actions/application/ShowSagittalViewer.cpp +++ b/sdk/actions/application/ShowSagittalViewer.cpp @@ -61,5 +61,6 @@ QWidget* ShowSagittalViewer::getWidget() { // --------------- apply ------------------- Action::ApplyStatus ShowSagittalViewer::apply() { MedicalImageViewer::getInstance()->setVisibleViewer(MedicalImageViewer::VIEWER_SAGITTAL); + Application::refresh(); return SUCCESS; } -- GitLab From 4314deda66b5ed6ccb75cc238fa48b4173ead911 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 17:46:10 +0100 Subject: [PATCH 08/15] FIXED update the tutorial to reflect viewer/mainwindow changes And add a screenshot action to the toolbar --- .../actions/switchviewer/BitmapViewer.cpp | 23 +++++++++++-------- tutorials/actions/switchviewer/BitmapViewer.h | 2 +- tutorials/actions/switchviewer/CMakeLists.txt | 3 +-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tutorials/actions/switchviewer/BitmapViewer.cpp b/tutorials/actions/switchviewer/BitmapViewer.cpp index 7cb6e39d..bef54c9f 100644 --- a/tutorials/actions/switchviewer/BitmapViewer.cpp +++ b/tutorials/actions/switchviewer/BitmapViewer.cpp @@ -61,7 +61,7 @@ BitmapViewer::BitmapViewer() : InteractiveViewer(BitmapViewerName, InteractiveVi getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); isVisible = false; - switchToolBar = nullptr; + switchToolbar = nullptr; } // -------------------- Destructor -------------------- @@ -102,23 +102,26 @@ QWidget* BitmapViewer::getWidget(QWidget* parent) { // -------------------- getToolBar -------------------- QToolBar* BitmapViewer::getToolBar() { - if (switchToolBar == nullptr) { + if (switchToolbar == nullptr) { + // create the toolbar and add the action to it + switchToolbar = new QToolBar(objectName() + " Toolbar"); + // ensure object name is set for saving the state + switchToolbar->setObjectName(objectName() + " Toolbar"); + + switchToolbar->addAction(screenshotAction); + // create the action to switch between the default and this viewer - QAction* switchViewerAction = new QAction(tr("Bitmap Viewer"), this); + QAction* switchViewerAction = new QAction(tr("Hide Bitmap Viewer"), this); switchViewerAction->setCheckable(true); switchViewerAction->setChecked(true); // first time getToolBar is called -> BitmapViewer is being displayed switchViewerAction->setStatusTip(tr("Switch The Central Viewer")); switchViewerAction->setWhatsThis(tr("Switch The Central Viewer between the BitmapViewer and MedicalImageViewer")); connect(switchViewerAction, SIGNAL(toggled(bool)), this, SLOT(switchCentralViewer())); - // create the toolbar and add the action to it - switchToolBar = new QToolBar(objectName() + " ToolBar"); - // ensure object name is set for saving the state - switchToolBar->setObjectName(objectName() + " ToolBar"); - - switchToolBar->addAction(switchViewerAction); + switchToolbar->addAction(switchViewerAction); + } - return switchToolBar; + return switchToolbar; } // -------------------- updateVisibility -------------------- diff --git a/tutorials/actions/switchviewer/BitmapViewer.h b/tutorials/actions/switchviewer/BitmapViewer.h index 4dd08b3c..a6c822e0 100644 --- a/tutorials/actions/switchviewer/BitmapViewer.h +++ b/tutorials/actions/switchviewer/BitmapViewer.h @@ -66,7 +66,7 @@ private: bool isVisible; - QToolBar* switchToolBar; + QToolBar* switchToolbar; // set visibility of all possible component (that is component that can be displayed in 2D) void updateVisibility(); diff --git a/tutorials/actions/switchviewer/CMakeLists.txt b/tutorials/actions/switchviewer/CMakeLists.txt index df9370bb..9cc3535d 100644 --- a/tutorials/actions/switchviewer/CMakeLists.txt +++ b/tutorials/actions/switchviewer/CMakeLists.txt @@ -1,2 +1 @@ -camitk_extension(ACTION_EXTENSION -) +camitk_extension(ACTION_EXTENSION) -- GitLab From 7b9dde9b15154bc86df3897c240c778047a50b79 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Mon, 4 Nov 2019 20:50:14 +0100 Subject: [PATCH 09/15] FIXED crash when using test application --- sdk/libraries/core/application/MainWindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/libraries/core/application/MainWindow.cpp b/sdk/libraries/core/application/MainWindow.cpp index be88de14..fc0bf12b 100644 --- a/sdk/libraries/core/application/MainWindow.cpp +++ b/sdk/libraries/core/application/MainWindow.cpp @@ -219,6 +219,9 @@ void MainWindow::showViewer(Viewer* theViewer, bool visible) { // ------------- showViewerToolbar ----------------- void MainWindow::showViewerToolbar(Viewer* theViewer, bool visible) { + if (theViewer == nullptr) + return; + QToolBar* viewerToolBar = theViewer->getToolBar(); if (viewerToolBar != nullptr) { if (visible && theViewer->getToolBarVisibility()) { -- GitLab From 4babb1d9811df348d6d19b4530c8a21f42c77ce8 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 07:05:39 +0100 Subject: [PATCH 10/15] FIXED update config-test There is now one additional action extension and one additional action --- sdk/applications/config/testing/config-test.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/applications/config/testing/config-test.sh b/sdk/applications/config/testing/config-test.sh index 520a06c2..5e3fae46 100644 --- a/sdk/applications/config/testing/config-test.sh +++ b/sdk/applications/config/testing/config-test.sh @@ -22,11 +22,11 @@ set -e # values to check initTestData() { # fill test data - extensionCount=( [4.2]=42 [4.1]=41 [4.0]=31 ) + extensionCount=( [4.2]=43 [4.1]=41 [4.0]=31 ) componentExtensionCount=( [4.2]=14 [4.1]=14 [4.0]=14 ) - actionExtensionCount=( [4.2]=28 [4.1]=27 [4.0]=27 ) + actionExtensionCount=( [4.2]=29 [4.1]=27 [4.0]=27 ) fileExtensionCount=( [4.2]=37 [4.1]=37 [4.0]=37 ) - actionCount=( [4.2]=106 [4.1]=105 [4.0]=105 ) + actionCount=( [4.2]=107 [4.1]=105 [4.0]=105 ) # fill release date releaseDate=( [4.2]="not yet released, current development version" \ -- GitLab From d8c8397f6fe215cb031d3e237bfcfe4326d65c82 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 07:37:55 +0100 Subject: [PATCH 11/15] NEW view menu has now a central viewer switcher When there is more than one central viewer, the "View" menu shows actions to switch from one central viewer to the other. --- sdk/applications/imp/ImpMainWindow.cpp | 56 ++++++++++++++++---------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/sdk/applications/imp/ImpMainWindow.cpp b/sdk/applications/imp/ImpMainWindow.cpp index 862b1b6f..0600efba 100644 --- a/sdk/applications/imp/ImpMainWindow.cpp +++ b/sdk/applications/imp/ImpMainWindow.cpp @@ -481,6 +481,10 @@ void ImpMainWindow::openDirectory(QAction* emitter) { // ------------- updateViewMenu ----------------- void ImpMainWindow::updateViewMenu() { + // From Qt documentation: + // "Removes all the menu's actions. Actions owned by the menu and not shown in any other widget are deleted" + // I.e., the central viewer toggle action are own by viewMenu (they are created and used here), they will + // therefore be no memory leak viewMenu->clear(); // insert viewers menu @@ -495,31 +499,41 @@ void ImpMainWindow::updateViewMenu() { // change the central viewer if there is more than one viewer in the central area if (qobject_cast(centralWidget())->count() > 1) { viewMenu->addSeparator()->setText(tr("Toggle Central Viewers")); - for(Viewer *v : viewers) { - int i = 0; - // beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() - // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) - // in order not to modify the central widget parenting - while (i(centralWidget())->count() && qobject_cast(centralWidget())->widget(i)!=v->getWidget(centralWidget())) - i++; - if (i(centralWidget())->count()) { - viewMenu->addAction(v->objectName()); - } - } - -// // add a toggle action -// for (int i = 0; i < qobject_cast(centralWidget())->count(); i++) { -// QWidget* cWidget = qobject_cast(centralWidget())->widget(i); -// // get the viewer associated with the widget in the central area +// for(Viewer *v : viewers) { +// int i = 0; // // beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() // // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) // // in order not to modify the central widget parenting -// auto it = std::find_if(viewers.begin(), viewers.end(), [cWidget,centralWidget=centralWidget()](Viewer * v) { -// return v->getWidget(centralWidget) == cWidget; -// }); -// Viewer* cViewer = (*it); -// viewMenu->addAction(cViewer->objectName()); +// while (i(centralWidget())->count() && qobject_cast(centralWidget())->widget(i)!=v->getWidget(centralWidget())) +// i++; +// if (i(centralWidget())->count()) { +// viewMenu->addAction(v->objectName()); +// } // } + + // add a toggle action + for (int i = 0; i < qobject_cast(centralWidget())->count(); i++) { + QWidget* cWidget = qobject_cast(centralWidget())->widget(i); + // get the viewer associated with the widget in the central area + // Beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() + // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) + // in order not to modify the central widget parenting + auto it = std::find_if(viewers.begin(), viewers.end(), [&](Viewer * v) { + return v->getWidget(centralWidget()) == cWidget; + }); + Viewer* cViewer = (*it); + // viewerAction is own by viewMenu, viewMenu->clear() will delete it + QAction *viewerAction = viewMenu->addAction(cViewer->objectName()); + viewerAction->setCheckable(true); + viewerAction->setChecked(cViewer == centralViewer); + QString tipString = "Hide/show the " + cViewer->objectName() + " central viewer"; + viewerAction->setStatusTip(tr(tipString.toStdString().c_str())); + viewerAction->setWhatsThis(tr(tipString.toStdString().c_str())); + // add the toggle action slot using C++11 lambda so that everything is contained inside viewMenu + connect(viewerAction, &QAction::toggled, [=](bool) { + setCentralViewer(cViewer); + }); + } } // insert viewers on/off actions -- GitLab From 805e952cf92e53e5eb015a9f1407f537d9797f66 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 07:38:42 +0100 Subject: [PATCH 12/15] NEW show an information dialog about the view menu This is only valid for imp and will only show the dialog once (first call) --- tutorials/actions/switchviewer/SwitchViewer.cpp | 11 +++++++---- tutorials/actions/switchviewer/SwitchViewer.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tutorials/actions/switchviewer/SwitchViewer.cpp b/tutorials/actions/switchviewer/SwitchViewer.cpp index 0ae24fa9..b677281d 100644 --- a/tutorials/actions/switchviewer/SwitchViewer.cpp +++ b/tutorials/actions/switchviewer/SwitchViewer.cpp @@ -25,12 +25,9 @@ #include "SwitchViewer.h" #include -#include -#include -#include -#include #include +#include using namespace camitk; @@ -44,6 +41,8 @@ SwitchViewer::SwitchViewer(ActionExtension* extension) : Action(extension) { setFamily("Tutorial"); addTag("Viewer"); addTag("MainWindow"); + + firstCall = true; } // --------------- getWidget ------------------- @@ -55,5 +54,9 @@ QWidget* SwitchViewer::getWidget() { Action::ApplyStatus SwitchViewer::apply() { // just ask the BitMap viewer to switch the central viewer BitmapViewer::getInstance()->switchCentralViewer(); + if (firstCall) { + QMessageBox::information(nullptr,"Switch Viewer From the Menu", "The next time you can also use the \"View Menu\" item \"Toggle Central Viewers\" to switch the central viewer from/to the Medical Image Viewer"); + firstCall = false; + } return SUCCESS; } diff --git a/tutorials/actions/switchviewer/SwitchViewer.h b/tutorials/actions/switchviewer/SwitchViewer.h index aa9519ad..15758c48 100644 --- a/tutorials/actions/switchviewer/SwitchViewer.h +++ b/tutorials/actions/switchviewer/SwitchViewer.h @@ -52,6 +52,7 @@ public slots: /// method called when the action is applied virtual ApplyStatus apply(); + bool firstCall; }; #endif // SWITCH_VIEWER_H -- GitLab From 9b054e667ef1bf9af3e7a74645836c1ea5744798 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 12:06:47 +0100 Subject: [PATCH 13/15] FIXED code cleanup --- sdk/applications/imp/ImpMainWindow.cpp | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/sdk/applications/imp/ImpMainWindow.cpp b/sdk/applications/imp/ImpMainWindow.cpp index 0600efba..6eccc8d0 100644 --- a/sdk/applications/imp/ImpMainWindow.cpp +++ b/sdk/applications/imp/ImpMainWindow.cpp @@ -499,22 +499,13 @@ void ImpMainWindow::updateViewMenu() { // change the central viewer if there is more than one viewer in the central area if (qobject_cast(centralWidget())->count() > 1) { viewMenu->addSeparator()->setText(tr("Toggle Central Viewers")); -// for(Viewer *v : viewers) { -// int i = 0; -// // beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() -// // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) -// // in order not to modify the central widget parenting -// while (i(centralWidget())->count() && qobject_cast(centralWidget())->widget(i)!=v->getWidget(centralWidget())) -// i++; -// if (i(centralWidget())->count()) { -// viewMenu->addAction(v->objectName()); -// } -// } - - // add a toggle action + + // add a toggle action for each widget stacked inside the central widget for (int i = 0; i < qobject_cast(centralWidget())->count(); i++) { QWidget* cWidget = qobject_cast(centralWidget())->widget(i); - // get the viewer associated with the widget in the central area + // Get the viewer associated with the widget in the central area + // As there is no map from widget to viewer, we need to find the viewer that + // has the given corresponding widget. // Beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget() // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this) // in order not to modify the central widget parenting -- GitLab From 02011557b1e3617ea76487c32022dea87398a87c Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 12:07:54 +0100 Subject: [PATCH 14/15] NEW renamed tutorial action now that MainWindow behaviour is specified The action does not switch to/from the bitmap viewer, it just shows it in the central viewer --- .../BitmapViewer.cpp | 55 ++++++------------- .../BitmapViewer.h | 8 +-- .../CMakeLists.txt | 0 .../ShowBitmapViewer.cpp} | 25 +++++---- .../ShowBitmapViewer.h} | 6 +- .../ShowBitmapViewerExtension.cpp} | 8 +-- .../ShowBitmapViewerExtension.h} | 20 +++---- 7 files changed, 51 insertions(+), 71 deletions(-) rename tutorials/actions/{switchviewer => bitmapviewer}/BitmapViewer.cpp (67%) rename tutorials/actions/{switchviewer => bitmapviewer}/BitmapViewer.h (94%) rename tutorials/actions/{switchviewer => bitmapviewer}/CMakeLists.txt (100%) rename tutorials/actions/{switchviewer/SwitchViewer.cpp => bitmapviewer/ShowBitmapViewer.cpp} (70%) rename tutorials/actions/{switchviewer/SwitchViewer.h => bitmapviewer/ShowBitmapViewer.h} (91%) rename tutorials/actions/{switchviewer/SwitchViewerExtension.cpp => bitmapviewer/ShowBitmapViewerExtension.cpp} (87%) rename tutorials/actions/{switchviewer/SwitchViewerExtension.h => bitmapviewer/ShowBitmapViewerExtension.h} (69%) diff --git a/tutorials/actions/switchviewer/BitmapViewer.cpp b/tutorials/actions/bitmapviewer/BitmapViewer.cpp similarity index 67% rename from tutorials/actions/switchviewer/BitmapViewer.cpp rename to tutorials/actions/bitmapviewer/BitmapViewer.cpp index bef54c9f..0000490c 100644 --- a/tutorials/actions/switchviewer/BitmapViewer.cpp +++ b/tutorials/actions/bitmapviewer/BitmapViewer.cpp @@ -32,7 +32,7 @@ #include -#include +#include // to change the camera projection to parallel using namespace camitk; @@ -60,31 +60,13 @@ BitmapViewer::BitmapViewer() : InteractiveViewer(BitmapViewerName, InteractiveVi // parallel projection getRendererWidget()->getActiveCamera()->ParallelProjectionOn(); - isVisible = false; - switchToolbar = nullptr; + myToolbar = nullptr; } // -------------------- Destructor -------------------- BitmapViewer::~BitmapViewer() { } -// -------------------- switchCentralViewer -------------------- -void BitmapViewer::switchCentralViewer() { - // if the central viewer is the medical image viewer switch to my2DBitmapViewer (if it is not switch back to the medical image viewer) - if (isVisible) { - // switch back to the default MedicalImageViewer - Application::getMainWindow()->setCentralViewer(MedicalImageViewer::getInstance()); - } - else { - // switch to the custom viewer - Application::getMainWindow()->setCentralViewer(BitmapViewer::getInstance()); - // force refresh - refresh(this); - } - - isVisible = !isVisible; -} - // -------------------- refresh -------------------- void BitmapViewer::refresh(Viewer* whoIsAsking) { updateVisibility(); @@ -102,28 +84,27 @@ QWidget* BitmapViewer::getWidget(QWidget* parent) { // -------------------- getToolBar -------------------- QToolBar* BitmapViewer::getToolBar() { - if (switchToolbar == nullptr) { + if (myToolbar == nullptr) { // create the toolbar and add the action to it - switchToolbar = new QToolBar(objectName() + " Toolbar"); + myToolbar = new QToolBar(objectName() + " Toolbar"); // ensure object name is set for saving the state - switchToolbar->setObjectName(objectName() + " Toolbar"); - - switchToolbar->addAction(screenshotAction); - - // create the action to switch between the default and this viewer - QAction* switchViewerAction = new QAction(tr("Hide Bitmap Viewer"), this); - switchViewerAction->setCheckable(true); - switchViewerAction->setChecked(true); // first time getToolBar is called -> BitmapViewer is being displayed - switchViewerAction->setStatusTip(tr("Switch The Central Viewer")); - switchViewerAction->setWhatsThis(tr("Switch The Central Viewer between the BitmapViewer and MedicalImageViewer")); - connect(switchViewerAction, SIGNAL(toggled(bool)), this, SLOT(switchCentralViewer())); - - switchToolbar->addAction(switchViewerAction); - + myToolbar->setObjectName(objectName() + " Toolbar"); + + myToolbar->addAction(screenshotAction); + + // create the action to switch back to the medical image viewer + QAction* hideViewerAction = myToolbar->addAction(tr("Hide Bitmap Viewer")); + hideViewerAction->setIcon(QPixmap(":/fileClose")); + hideViewerAction->setStatusTip(tr("Switch back to the medical image viewer")); + hideViewerAction->setWhatsThis(tr("Switch back the ventral viewer to normal (i.e., show the Medical Image Viewer)")); + connect(hideViewerAction, &QAction::triggered, [=](bool) { + Application::getMainWindow()->setCentralViewer(MedicalImageViewer::getInstance()); + }); } - return switchToolbar; + return myToolbar; } + // -------------------- updateVisibility -------------------- void BitmapViewer::updateVisibility() { // as the default component does not know anything about my2DBitmapViewer, diff --git a/tutorials/actions/switchviewer/BitmapViewer.h b/tutorials/actions/bitmapviewer/BitmapViewer.h similarity index 94% rename from tutorials/actions/switchviewer/BitmapViewer.h rename to tutorials/actions/bitmapviewer/BitmapViewer.h index a6c822e0..b7cb7a59 100644 --- a/tutorials/actions/switchviewer/BitmapViewer.h +++ b/tutorials/actions/bitmapviewer/BitmapViewer.h @@ -50,10 +50,6 @@ public: QToolBar* getToolBar() override; -public slots: - - void switchCentralViewer(); - protected: BitmapViewer(); @@ -64,9 +60,7 @@ private: static QString BitmapViewerName; - bool isVisible; - - QToolBar* switchToolbar; + QToolBar* myToolbar; // set visibility of all possible component (that is component that can be displayed in 2D) void updateVisibility(); diff --git a/tutorials/actions/switchviewer/CMakeLists.txt b/tutorials/actions/bitmapviewer/CMakeLists.txt similarity index 100% rename from tutorials/actions/switchviewer/CMakeLists.txt rename to tutorials/actions/bitmapviewer/CMakeLists.txt diff --git a/tutorials/actions/switchviewer/SwitchViewer.cpp b/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp similarity index 70% rename from tutorials/actions/switchviewer/SwitchViewer.cpp rename to tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp index b677281d..96436116 100644 --- a/tutorials/actions/switchviewer/SwitchViewer.cpp +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp @@ -23,37 +23,42 @@ * $CAMITK_LICENCE_END$ ****************************************************************************/ -#include "SwitchViewer.h" -#include +#include "ShowBitmapViewer.h" +#include "BitmapViewer.h" + +#include +#include #include #include using namespace camitk; -// -------------------- SwitchViewer -------------------- -SwitchViewer::SwitchViewer(ActionExtension* extension) : Action(extension) { - setName("Switch Central Viewer"); +// -------------------- ShowBitmapViewer -------------------- +ShowBitmapViewer::ShowBitmapViewer(ActionExtension* extension) : Action(extension) { + setName("Show Bitmap Viewer"); setEmbedded(false); // not embedded (and as the - setDescription("Tutorial action that switch the central viewer in/out. Trigger this action when no component is selected"); + setDescription("Tutorial action that set the bitmap viewer as the central viewer. Trigger this action when no component is selected"); setComponent(""); setFamily("Tutorial"); addTag("Viewer"); + addTag("BitmapViewer"); addTag("MainWindow"); firstCall = true; } // --------------- getWidget ------------------- -QWidget* SwitchViewer::getWidget() { +QWidget* ShowBitmapViewer::getWidget() { return nullptr; } // --------------- apply ------------------- -Action::ApplyStatus SwitchViewer::apply() { - // just ask the BitMap viewer to switch the central viewer - BitmapViewer::getInstance()->switchCentralViewer(); +Action::ApplyStatus ShowBitmapViewer::apply() { + // just add the BitMap viewer in the central viewer + Application::getMainWindow()->setCentralViewer(BitmapViewer::getInstance()); + Application::refresh(); if (firstCall) { QMessageBox::information(nullptr,"Switch Viewer From the Menu", "The next time you can also use the \"View Menu\" item \"Toggle Central Viewers\" to switch the central viewer from/to the Medical Image Viewer"); firstCall = false; diff --git a/tutorials/actions/switchviewer/SwitchViewer.h b/tutorials/actions/bitmapviewer/ShowBitmapViewer.h similarity index 91% rename from tutorials/actions/switchviewer/SwitchViewer.h rename to tutorials/actions/bitmapviewer/ShowBitmapViewer.h index 15758c48..aea4b2b0 100644 --- a/tutorials/actions/switchviewer/SwitchViewer.h +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewer.h @@ -36,14 +36,14 @@ class Viewer; /** * Demonstrates how to switch the central image viewer. */ -class SwitchViewer : public camitk::Action { +class ShowBitmapViewer : public camitk::Action { public: /// the constructor - SwitchViewer(camitk::ActionExtension*); + ShowBitmapViewer(camitk::ActionExtension*); /// the destructor - virtual ~SwitchViewer() = default; + virtual ~ShowBitmapViewer() = default; /// method called when the action when the action is triggered (i.e. started) virtual QWidget* getWidget(); diff --git a/tutorials/actions/switchviewer/SwitchViewerExtension.cpp b/tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.cpp similarity index 87% rename from tutorials/actions/switchviewer/SwitchViewerExtension.cpp rename to tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.cpp index cb40f43c..ec10627b 100644 --- a/tutorials/actions/switchviewer/SwitchViewerExtension.cpp +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.cpp @@ -22,11 +22,11 @@ * * $CAMITK_LICENCE_END$ ****************************************************************************/ -#include "SwitchViewerExtension.h" -#include "SwitchViewer.h" +#include "ShowBitmapViewerExtension.h" +#include "ShowBitmapViewer.h" // -------------------- init -------------------- -void SwitchViewerExtension::init() { - registerNewAction(SwitchViewer); +void ShowBitmapViewerExtension::init() { + registerNewAction(ShowBitmapViewer); } diff --git a/tutorials/actions/switchviewer/SwitchViewerExtension.h b/tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.h similarity index 69% rename from tutorials/actions/switchviewer/SwitchViewerExtension.h rename to tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.h index 042266d7..24800fd8 100644 --- a/tutorials/actions/switchviewer/SwitchViewerExtension.h +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewerExtension.h @@ -24,39 +24,39 @@ ****************************************************************************/ -#ifndef SWITCH_VIEWER_EXTENSION_H -#define SWITCH_VIEWER_EXTENSION_H +#ifndef SHOW_BITMAP_VIEWER_EXTENSION_H +#define SHOW_BITMAP_VIEWER_EXTENSION_H #include #include #include -/// shows how to switch the central viewer in and out -class SwitchViewerExtension : public camitk::ActionExtension { +/// shows the bitmap viewer in the central viewer +class ShowBitmapViewerExtension : public camitk::ActionExtension { Q_OBJECT Q_INTERFACES(camitk::ActionExtension) - Q_PLUGIN_METADATA(IID "fr.imag.camitk.tutorials.action.switchviewer") + Q_PLUGIN_METADATA(IID "fr.imag.camitk.tutorials.action.showbitmapviewer") public: /// the constructor - SwitchViewerExtension() : ActionExtension() {}; + ShowBitmapViewerExtension() : ActionExtension() {}; /// the destructor - virtual ~SwitchViewerExtension() = default; + virtual ~ShowBitmapViewerExtension() = default; /// initialize all the actions virtual void init(); /// Method that return the action extension name virtual QString getName() { - return "Switch Viewer"; + return "Show Bitmap Viewer"; }; /// Method that return the action extension descrption virtual QString getDescription() { - return "This extension contains a simple medical image viewer (axial slice) and a simple action to switch the central viewer (by default, the medical image viewer) to and from the simple medical image viewer."; + return "This extension contains a simple 2D bitmap viewer and a simple action to show this bitmap viewer in the central viewer."; }; }; -#endif // BASIC_PICKING_EXTENSION_H +#endif // SHOW_BITMAP_VIEWER_EXTENSION_H -- GitLab From d908b897bab2fc0af9e5db8b37d236ffa3620941 Mon Sep 17 00:00:00 2001 From: Emmanuel Promayon Date: Tue, 5 Nov 2019 15:05:41 +0100 Subject: [PATCH 15/15] FIXED code cleanup --- tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp | 3 ++- tutorials/actions/bitmapviewer/ShowBitmapViewer.h | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp b/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp index 96436116..9d92d29c 100644 --- a/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewer.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -60,7 +61,7 @@ Action::ApplyStatus ShowBitmapViewer::apply() { Application::getMainWindow()->setCentralViewer(BitmapViewer::getInstance()); Application::refresh(); if (firstCall) { - QMessageBox::information(nullptr,"Switch Viewer From the Menu", "The next time you can also use the \"View Menu\" item \"Toggle Central Viewers\" to switch the central viewer from/to the Medical Image Viewer"); + CAMITK_INFO("TIP: switch central wiewers from the menu: do you know that you can use the \"View Menu\" item \"Toggle Central Viewers\" to switch the central viewer from/to the Medical Image Viewer"); firstCall = false; } return SUCCESS; diff --git a/tutorials/actions/bitmapviewer/ShowBitmapViewer.h b/tutorials/actions/bitmapviewer/ShowBitmapViewer.h index aea4b2b0..fc56562e 100644 --- a/tutorials/actions/bitmapviewer/ShowBitmapViewer.h +++ b/tutorials/actions/bitmapviewer/ShowBitmapViewer.h @@ -23,8 +23,8 @@ * $CAMITK_LICENCE_END$ ****************************************************************************/ -#ifndef SWITCH_VIEWER_H -#define SWITCH_VIEWER_H +#ifndef SHOW_BITMAP_VIEWER_H +#define SHOW_BITMAP_VIEWER_H #include @@ -55,4 +55,4 @@ public slots: bool firstCall; }; -#endif // SWITCH_VIEWER_H +#endif // SHOW_BITMAP_VIEWER_H -- GitLab