Skip to content

Commit

Permalink
ENH: Initial VR home widget implementation
Browse files Browse the repository at this point in the history
This commit is intended to implement features described in #43
by integrating changes originally associated with the following
branches:

* dgmato/gui-widgets-interactions
  - initially developed between 2021-12-15 and 2022-05-23 by @dgmato
    with contributions from @cpinter.
  - based on the "gui-widgets-module" branch

* dgmato/gui-widgets-module
  - initially developed between 2018-10-18 and 2021-10-0523 by @cpinter
    with contributions from @dgmato, @lassoan, @SalehChoueib and @mohammadrashid0917
  - with first commit titled "ENH: Initial VR home widget implementation"
    based of "dgmato/virtual-widget" branch.

* dgmato/virtual-widget
  - initial commit contributed by @SalehChoueib on 2018-10-18 (ENH: Add virtual widget
    from arbitrary Qt Widget !WIP!)
  - follow-up development by @cpinter and @mohammadrashid0917
    between 2019-05-13 and 2019-06-13

------------
Commits originally associated with branch "dgmato/gui-widgets-interactions":

* ENH: Remove unused UI widget in GUI Widgets module

* ENH: Do not load avatar models when setting up VR pointer

* ENH: Add new button to set up interaction
  Set up will include getting the VR controller transform node and applying that transform to the pointer model.

* ENH: Add GUIWidgets module to Virtual Reality category for easy access

* ENH: Load avatar models and transform pointer by right controller transform

* ENH: Reorganize code and remove unused code

* COMP: Fix build error due to Slicer API changes

* ENH: Add new module target library
  vtkSlicerMarkupsModuleMRMLDisplayableManager

* ENH: Send mouse release event to complete simulated mouse click after press event

* ENH: Modify coordinate system for GUI widget
  Origin is located on the top left corner in Qt widgets.

* ENH: Add button "Start interaction" to simulate interaction with VR pointer

* ENH: Add module to simulate VR pointer display and movement

------------
Commits originally associated with branch "dgmato/gui-widgets-module":

* ENH: Add buttons in GUIWidgets to show VR widgets; Fix include dirs variable in CMake

* ENH: Add GUIWidgets module that provides in-VR Qt widget

  This is still a prototype, a few crucial features are needed:
  - Handle mouse interactions on the widget: forward events to Qt
  - Support moving the widget to arbitrary position
    - Implement outline tube and handle to grab with the controller
    - Option to keep widget floating in certain position relative to head motion (~HUD)
  - Implement laser pointer and use the intersection with these widgets as mouse interaction

  See more history: https://github.com/cpinter/VtkQWidgetTest

* ENH: Creating and registering VR segment editor widget
  Creates and registers the VR segment editor widget (which can be switched to from the VR home widget)

* BUG: Fix issues in VR home widget and the data widget

* ENH: Creating and registering VR data module widget
  Creates and registers the VR data module widget (which can be switched to from the VR home widget)

* ENH: Convert the interactor style to use the new vtkMRMLViewInteractorStyle
  Fix build error with Slicer-4.10

* STYLE: Add function documentation

* ENH: Initial VR home widget implementation

  Squashed commits (originally associated with branch "dgmato/virtual-widget")

  * ENH: Create framework for registering VR modules
    Adds registerModule function to qMRMLVRView which can be called to create a new button for that module on the Modules bar in the VR home widget

  * ENH: Make VR home widget controls functional
    These changes make it so that changes in the module widget (viewable in Slicer) are reflected in the home widget (viewable in VR) and vice versa

  * ENH: Add VR optimized Qt Style Sheet
    This style sheet makes the text in the VR menu widget bigger, and gives the buttons and slider handles different colors for unpressed, hover, and pressed statuses.

  * ENH: Add VR home widget WIP
    Its UI is more or less complete but events are not handled and style sheet is needed

  * ENH: Add virtual widget from arbitrary Qt Widget !WIP!

Co-authored-by: Andras Lasso <[email protected]>
Co-authored-by: Csaba Pinter <[email protected]>
Co-authored-by: David Garcia Mato <[email protected]>
Co-authored-by: Mohammad Rashid <[email protected]>
Co-authored-by: Sal Choueib <[email protected]>
  • Loading branch information
5 people authored and jcfr committed Oct 13, 2022
1 parent 3106905 commit b4b5598
Show file tree
Hide file tree
Showing 58 changed files with 6,003 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ endif()
#-----------------------------------------------------------------------------
# Extension modules
add_subdirectory(VirtualReality)
add_subdirectory(GUIWidgets)
add_subdirectory(PointerSimulator)
## NEXT_MODULE

#-----------------------------------------------------------------------------
Expand Down
81 changes: 81 additions & 0 deletions GUIWidgets/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@

#-----------------------------------------------------------------------------
set(MODULE_NAME GUIWidgets)
set(MODULE_TITLE ${MODULE_NAME})

string(TOUPPER ${MODULE_NAME} MODULE_NAME_UPPER)

#-----------------------------------------------------------------------------
add_subdirectory(MRML)
add_subdirectory(Logic)
add_subdirectory(VTKWidgets)
# add_subdirectory(MRMLDM)
# add_subdirectory(Widgets)

#-----------------------------------------------------------------------------
set(MODULE_EXPORT_DIRECTIVE "Q_SLICER_QTMODULES_${MODULE_NAME_UPPER}_EXPORT")

# Current_{source,binary} and Slicer_{Libs,Base} already included
set(MODULE_INCLUDE_DIRECTORIES
${CMAKE_CURRENT_SOURCE_DIR}/MRML
${CMAKE_CURRENT_BINARY_DIR}/MRML
${CMAKE_CURRENT_SOURCE_DIR}/Logic
${CMAKE_CURRENT_BINARY_DIR}/Logic
${CMAKE_CURRENT_SOURCE_DIR}/VTKWidgets
${CMAKE_CURRENT_BINARY_DIR}/VTKWidgets
# ${CMAKE_CURRENT_SOURCE_DIR}/Widgets
# ${CMAKE_CURRENT_BINARY_DIR}/Widgets
${qSlicerMarkupsModuleWidgets_INCLUDE_DIRS}
${qSlicerVirtualRealityModuleWidgets_INCLUDE_DIRS}
)

set(MODULE_SRCS
qSlicer${MODULE_NAME}Module.cxx
qSlicer${MODULE_NAME}Module.h
qSlicer${MODULE_NAME}ModuleWidget.cxx
qSlicer${MODULE_NAME}ModuleWidget.h
)

set(MODULE_MOC_SRCS
qSlicer${MODULE_NAME}Module.h
qSlicer${MODULE_NAME}ModuleWidget.h
)

set(MODULE_UI_SRCS
Resources/UI/qSlicer${MODULE_NAME}ModuleWidget.ui
)

set(MODULE_TARGET_LIBRARIES
vtkSlicer${MODULE_NAME}ModuleMRML
vtkSlicer${MODULE_NAME}ModuleLogic
vtkSlicer${MODULE_NAME}ModuleVTKWidgets
# vtkSlicer${MODULE_NAME}ModuleMRMLDisplayableManager
# qSlicer${MODULE_NAME}ModuleWidgets
vtkSlicerMarkupsModuleMRMLDisplayableManager
qSlicerMarkupsModuleWidgets
qSlicerVirtualRealityModuleWidgets
vtkSlicerVirtualRealityModuleLogic
)

set(MODULE_RESOURCES
Resources/qSlicer${MODULE_NAME}Module.qrc
)

#-----------------------------------------------------------------------------
slicerMacroBuildLoadableModule(
NAME ${MODULE_NAME}
TITLE ${MODULE_TITLE}
EXPORT_DIRECTIVE ${MODULE_EXPORT_DIRECTIVE}
INCLUDE_DIRECTORIES ${MODULE_INCLUDE_DIRECTORIES}
SRCS ${MODULE_SRCS}
MOC_SRCS ${MODULE_MOC_SRCS}
UI_SRCS ${MODULE_UI_SRCS}
TARGET_LIBRARIES ${MODULE_TARGET_LIBRARIES}
RESOURCES ${MODULE_RESOURCES}
WITH_GENERIC_TESTS
)

#-----------------------------------------------------------------------------
if(BUILD_TESTING)
add_subdirectory(Testing)
endif()
27 changes: 27 additions & 0 deletions GUIWidgets/Logic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
project(vtkSlicer${MODULE_NAME}ModuleLogic)

set(KIT ${PROJECT_NAME})

set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_LOGIC_EXPORT")

set(${KIT}_INCLUDE_DIRECTORIES
)

set(${KIT}_SRCS
vtkSlicer${MODULE_NAME}Logic.cxx
vtkSlicer${MODULE_NAME}Logic.h
)

set(${KIT}_TARGET_LIBRARIES
vtkSlicer${MODULE_NAME}ModuleMRML
vtkSlicerMarkupsModuleLogic
)

#-----------------------------------------------------------------------------
SlicerMacroBuildModuleLogic(
NAME ${KIT}
EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE}
INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES}
SRCS ${${KIT}_SRCS}
TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES}
)
143 changes: 143 additions & 0 deletions GUIWidgets/Logic/vtkSlicerGUIWidgetsLogic.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*==============================================================================
Program: 3D Slicer
Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// GUIWidgets Logic includes
#include "vtkSlicerGUIWidgetsLogic.h"

// GUIWidgets MRML includes
#include "vtkMRMLGUIWidgetNode.h"
#include "vtkMRMLGUIWidgetDisplayNode.h"

// MRML includes
#include <vtkMRMLScene.h>
#include <vtkMRMLSelectionNode.h>

// Markups logic includes
#include <vtkSlicerMarkupsLogic.h>

// VTK includes
#include <vtkIntArray.h>
#include <vtkNew.h>
#include <vtkObjectFactory.h>

// STD includes
#include <cassert>

//----------------------------------------------------------------------------
vtkStandardNewMacro(vtkSlicerGUIWidgetsLogic);

//----------------------------------------------------------------------------
vtkSlicerGUIWidgetsLogic::vtkSlicerGUIWidgetsLogic()
{
}

//----------------------------------------------------------------------------
vtkSlicerGUIWidgetsLogic::~vtkSlicerGUIWidgetsLogic()
{
}

//----------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}

//---------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::SetMRMLSceneInternal(vtkMRMLScene * newScene)
{
vtkNew<vtkIntArray> events;
events->InsertNextValue(vtkMRMLScene::NodeAddedEvent);
events->InsertNextValue(vtkMRMLScene::NodeRemovedEvent);
events->InsertNextValue(vtkMRMLScene::EndBatchProcessEvent);
this->SetAndObserveMRMLSceneEventsInternal(newScene, events.GetPointer());
}

//---------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::ObserveMRMLScene()
{
if (!this->GetMRMLScene())
{
return;
}

vtkMRMLApplicationLogic* mrmlAppLogic = this->GetMRMLApplicationLogic();
if (!mrmlAppLogic)
{
vtkErrorMacro("ObserveMRMLScene: invalid MRML Application Logic");
return;
}

vtkMRMLNode* node = this->GetMRMLScene()->GetNodeByID(this->GetSelectionNodeID().c_str());
if (!node)
{
vtkErrorMacro("Observe MRMLScene: invalid Selection Node");
return;
}

// add known markup types to the selection node
vtkMRMLSelectionNode* selectionNode = vtkMRMLSelectionNode::SafeDownCast(node);
if (selectionNode)
{
// got into batch process mode so that an update on the mouse mode tool
// bar is triggered when leave it
this->GetMRMLScene()->StartState(vtkMRMLScene::BatchProcessState);

auto guiWidgetNode = vtkSmartPointer<vtkMRMLGUIWidgetNode>::New();
selectionNode->AddNewPlaceNodeClassNameToList(
guiWidgetNode->GetClassName(), guiWidgetNode->GetAddIcon(), guiWidgetNode->GetMarkupType());

// trigger an update on the mouse mode toolbar
this->GetMRMLScene()->EndState(vtkMRMLScene::BatchProcessState);
}

this->Superclass::ObserveMRMLScene();
}

//-----------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::RegisterNodes()
{
vtkMRMLScene* scene = this->GetMRMLScene();
if (!scene)
{
vtkErrorMacro("RegisterNodes: Invalid MRML scene");
return;
}
if (!scene->IsNodeClassRegistered("vtkMRMLGUIWidgetNode"))
{
scene->RegisterNodeClass(vtkSmartPointer<vtkMRMLGUIWidgetNode>::New());
}
if (!scene->IsNodeClassRegistered("vtkMRMLGUIWidgetDisplayNode"))
{
scene->RegisterNodeClass(vtkSmartPointer<vtkMRMLGUIWidgetDisplayNode>::New());
}
}

//---------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::UpdateFromMRMLScene()
{
assert(this->GetMRMLScene() != 0);
}

//---------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::OnMRMLSceneNodeAdded(vtkMRMLNode* vtkNotUsed(node))
{
}

//---------------------------------------------------------------------------
void vtkSlicerGUIWidgetsLogic::OnMRMLSceneNodeRemoved(vtkMRMLNode* vtkNotUsed(node))
{
}
63 changes: 63 additions & 0 deletions GUIWidgets/Logic/vtkSlicerGUIWidgetsLogic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*==============================================================================
Program: 3D Slicer
Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// .NAME vtkSlicerGUIWidgetsLogic - slicer logic class for volumes manipulation
// .SECTION Description
// This class manages the logic associated with reading, saving,
// and changing propertied of the volumes


#ifndef __vtkSlicerGUIWidgetsLogic_h
#define __vtkSlicerGUIWidgetsLogic_h

// Slicer includes
#include <vtkSlicerMarkupsLogic.h>

// MRML includes

#include "vtkSlicerGUIWidgetsModuleLogicExport.h"

/// \ingroup Slicer_QtModules_ExtensionTemplate
class VTK_SLICER_GUIWIDGETS_MODULE_LOGIC_EXPORT vtkSlicerGUIWidgetsLogic :
public vtkSlicerMarkupsLogic
{
public:

static vtkSlicerGUIWidgetsLogic *New();
vtkTypeMacro(vtkSlicerGUIWidgetsLogic, vtkSlicerMarkupsLogic);
void PrintSelf(ostream& os, vtkIndent indent);

protected:
vtkSlicerGUIWidgetsLogic();
virtual ~vtkSlicerGUIWidgetsLogic();

/// Initialize listening to MRML events
virtual void SetMRMLSceneInternal(vtkMRMLScene* newScene);
void ObserveMRMLScene() override;

/// Register MRML Node classes to Scene. Gets called automatically when the MRMLScene is attached to this logic class.
virtual void RegisterNodes();
virtual void UpdateFromMRMLScene();
virtual void OnMRMLSceneNodeAdded(vtkMRMLNode* node);
virtual void OnMRMLSceneNodeRemoved(vtkMRMLNode* node);
private:

vtkSlicerGUIWidgetsLogic(const vtkSlicerGUIWidgetsLogic&); // Not implemented
void operator=(const vtkSlicerGUIWidgetsLogic&); // Not implemented
};

#endif
29 changes: 29 additions & 0 deletions GUIWidgets/MRML/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
project(vtkSlicer${MODULE_NAME}ModuleMRML)

set(KIT ${PROJECT_NAME})

set(${KIT}_EXPORT_DIRECTIVE "VTK_SLICER_${MODULE_NAME_UPPER}_MODULE_MRML_EXPORT")

set(${KIT}_INCLUDE_DIRECTORIES
${vtkSlicer${MODULE_NAME}ModuleVTKWidgets_SOURCE_DIR}
${vtkSlicer${MODULE_NAME}ModuleVTKWidgets_BINARY_DIR}
)

set(${KIT}_SRCS
vtkMRMLGUIWidgetNode.cxx
vtkMRMLGUIWidgetDisplayNode.cxx
)

set(${KIT}_TARGET_LIBRARIES
${MRML_LIBRARIES}
vtkSlicerMarkupsModuleMRML
)

#-----------------------------------------------------------------------------
SlicerMacroBuildModuleMRML(
NAME ${KIT}
EXPORT_DIRECTIVE ${${KIT}_EXPORT_DIRECTIVE}
INCLUDE_DIRECTORIES ${${KIT}_INCLUDE_DIRECTORIES}
SRCS ${${KIT}_SRCS}
TARGET_LIBRARIES ${${KIT}_TARGET_LIBRARIES}
)
35 changes: 35 additions & 0 deletions GUIWidgets/MRML/vtkMRMLGUIWidgetDisplayNode.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*==============================================================================
Program: 3D Slicer
Portions (c) Copyright Brigham and Women's Hospital (BWH) All Rights Reserved.
See COPYRIGHT.txt
or http://www.slicer.org/copyright/copyright.txt for details.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
This file was originally developed by Csaba Pinter, EBATINCA, S.L., and
development was supported by "ICEX Espana Exportacion e Inversiones" under
the program "Inversiones de Empresas Extranjeras en Actividades de I+D
(Fondo Tecnologico)- Convocatoria 2021"
==============================================================================*/

// MRML includes
#include "vtkMRMLGUIWidgetDisplayNode.h"

//----------------------------------------------------------------------------
vtkMRMLNodeNewMacro(vtkMRMLGUIWidgetDisplayNode);

//----------------------------------------------------------------------------
vtkMRMLGUIWidgetDisplayNode::vtkMRMLGUIWidgetDisplayNode()
{
}

//----------------------------------------------------------------------------
vtkMRMLGUIWidgetDisplayNode::~vtkMRMLGUIWidgetDisplayNode() = default;
Loading

0 comments on commit b4b5598

Please sign in to comment.