Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Enable right-click menu for fiducials #1253

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Libs/MRML/Core/vtkMRMLDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ class VTK_MRML_EXPORT vtkMRMLDisplayNode : public vtkMRMLNode
NUM_SCALAR_RANGE_FLAGS
} ScalarRangeFlagType;

enum
{
MenuEvent = 16100, /**< display of context menu is requested (mapped to right-click by default),
event data is vtkMRMLInteractionEventData */
};

/// Convert between scalar range flag type id and string
/// \sa ScalarRangeFlag
static const char* GetScalarRangeFlagTypeAsString(int flag);
Expand Down
2 changes: 0 additions & 2 deletions Modules/Loadable/Markups/MRML/vtkMRMLMarkupsDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,6 @@ class VTK_SLICER_MARKUPS_MODULE_MRML_EXPORT vtkMRMLMarkupsDisplayNode : public
ResetToDefaultsEvent = 19001, //< reset this node to the default values, request completed by markups logic
JumpToPointEvent, /**< request jump to a selected control point, request completed by markups logic,
event data is vtkMRMLInteractionEventData*/
MenuEvent, /**< display of context menu is requested (mapped to right-click by default),
event data is vtkMRMLInteractionEventData */
ActionEvent, /**< default action on the point is requested (mapped to double-click by default),
event data is vtkMRMLInteractionEventData */
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ set(KIT ${PROJECT_NAME})
set(${KIT}_EXPORT_DIRECTIVE "Q_SLICER_${MODULE_NAME_UPPER}_SUBJECT_HIERARCHY_PLUGINS_EXPORT")

set(${KIT}_INCLUDE_DIRECTORIES
${vtkSlicerMarkupsModuleMRML_INCLUDE_DIRS}
${qSlicerSubjectHierarchyModuleWidgets_INCLUDE_DIRS}
${vtkSlicerSubjectHierarchyModuleLogic_INCLUDE_DIRS}
${qSlicerTerminologiesModuleWidgets_INCLUDE_DIRS}
Expand Down Expand Up @@ -33,6 +34,7 @@ set(${KIT}_RESOURCES

#-----------------------------------------------------------------------------
set(${KIT}_TARGET_LIBRARIES
vtkSlicer${MODULE_NAME}ModuleMRML
qSlicerSubjectHierarchyModuleWidgets
vtkSlicerSubjectHierarchyModuleLogic
qSlicerTerminologiesModuleWidgets
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
// MRML includes
#include <vtkMRMLDisplayableNode.h>
#include <vtkMRMLDisplayNode.h>
#include <vtkMRMLMarkupsFiducialNode.h>
#include <vtkMRMLScene.h>

// vtkSegmentationCore includes
Expand All @@ -50,6 +51,7 @@

// Qt includes
#include <QDebug>
#include <QInputDialog>
#include <QStandardItem>
#include <QAction>

Expand All @@ -67,6 +69,11 @@ class qSlicerSubjectHierarchyMarkupsPluginPrivate: public QObject
qSlicerSubjectHierarchyMarkupsPluginPrivate(qSlicerSubjectHierarchyMarkupsPlugin& object);
~qSlicerSubjectHierarchyMarkupsPluginPrivate() override;
void init();

public:
QAction* RenameFiducialAction;

QVariantMap ViewMenuEventData;
};

//-----------------------------------------------------------------------------
Expand All @@ -76,11 +83,16 @@ class qSlicerSubjectHierarchyMarkupsPluginPrivate: public QObject
qSlicerSubjectHierarchyMarkupsPluginPrivate::qSlicerSubjectHierarchyMarkupsPluginPrivate(qSlicerSubjectHierarchyMarkupsPlugin& object)
: q_ptr(&object)
{
this->RenameFiducialAction = nullptr;
}

//------------------------------------------------------------------------------
void qSlicerSubjectHierarchyMarkupsPluginPrivate::init()
{
Q_Q(qSlicerSubjectHierarchyMarkupsPlugin);

this->RenameFiducialAction = new QAction("Rename fiducial...", q);
QObject::connect(this->RenameFiducialAction, SIGNAL(triggered()), q, SLOT(renameFiducial()));
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -351,3 +363,84 @@ QColor qSlicerSubjectHierarchyMarkupsPlugin::getDisplayColor(vtkIdType itemID, Q
double* colorArray = displayNode->GetSelectedColor();
return QColor::fromRgbF(colorArray[0], colorArray[1], colorArray[2]);
}

//-----------------------------------------------------------------------------
QList<QAction*> qSlicerSubjectHierarchyMarkupsPlugin::viewContextMenuActions()const
{
Q_D(const qSlicerSubjectHierarchyMarkupsPlugin);

QList<QAction*> actions;
actions << d->RenameFiducialAction;
return actions;
}

//-----------------------------------------------------------------------------
void qSlicerSubjectHierarchyMarkupsPlugin::showViewContextMenuActionsForItem(vtkIdType itemID, QVariantMap eventData)
{
Q_D(qSlicerSubjectHierarchyMarkupsPlugin);

if (itemID == vtkMRMLSubjectHierarchyNode::INVALID_ITEM_ID)
{
qCritical() << Q_FUNC_INFO << ": Invalid input item";
return;
}
vtkMRMLSubjectHierarchyNode* shNode = qSlicerSubjectHierarchyPluginHandler::instance()->subjectHierarchyNode();
if (!shNode)
{
qCritical() << Q_FUNC_INFO << ": Failed to access subject hierarchy node";
return;
}

// Markup
vtkMRMLNode* associatedNode = shNode->GetItemDataNode(itemID);
if (associatedNode && associatedNode->IsA("vtkMRMLMarkupsFiducialNode"))
{
d->ViewMenuEventData = eventData;
d->ViewMenuEventData["NodeID"] = QVariant(associatedNode->GetID());

d->RenameFiducialAction->setVisible(true);
}
}

//-----------------------------------------------------------------------------
void qSlicerSubjectHierarchyMarkupsPlugin::renameFiducial()
{
Q_D(qSlicerSubjectHierarchyMarkupsPlugin);

if (d->ViewMenuEventData.find("NodeID") == d->ViewMenuEventData.end())
{
qCritical() << Q_FUNC_INFO << ": No node ID found in the view menu event data";
return;
}
vtkMRMLScene* scene = qSlicerSubjectHierarchyPluginHandler::instance()->mrmlScene();
if (!scene)
{
qCritical() << Q_FUNC_INFO << ": Failed to access MRML scene";
return;
}

// Get fiducial markups node
QString nodeID = d->ViewMenuEventData["NodeID"].toString();
vtkMRMLNode* node = scene->GetNodeByID(nodeID.toLatin1().constData());
vtkMRMLMarkupsFiducialNode* fiducialNode = vtkMRMLMarkupsFiducialNode::SafeDownCast(node);
if (!fiducialNode)
{
qCritical() << Q_FUNC_INFO << ": Failed to get fiducial markups node by ID " << nodeID;
return;
}

// Get fiducial index
int componentIndex = d->ViewMenuEventData["ComponentIndex"].toInt();

// Pop up an entry box for the new name, with the old name as default
QString oldName(fiducialNode->GetNthFiducialLabel(componentIndex).c_str());

bool ok = false;
QString newName = QInputDialog::getText(nullptr, QString("Rename ") + oldName, "New name:", QLineEdit::Normal, oldName, &ok);
if (!ok)
{
return;
}

fiducialNode->SetNthFiducialLabel(componentIndex, newName.toLatin1().constData());
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ class Q_SLICER_MARKUPS_SUBJECT_HIERARCHY_PLUGINS_EXPORT qSlicerSubjectHierarchyM
/// qSlicerTerminologyItemDelegate::ColorAutoGeneratedRole : bool
QColor getDisplayColor(vtkIdType itemID, QMap<int, QVariant> &terminologyMetaData)const override;

/// Get view context menu item actions that are available when right-clicking an object in the views.
/// These item context menu actions can be shown in the implementations of \sa showViewContextMenuActionsForItem
QList<QAction*> viewContextMenuActions()const override;

/// Show context menu actions valid for a given subject hierarchy item to be shown in the view.
/// \param itemID Subject Hierarchy item to show the context menu items for
/// \param eventData Supplementary data for the item that may be considered for the menu (sub-item ID, attribute, etc.)
void showViewContextMenuActionsForItem(vtkIdType itemID, QVariantMap eventData) override;

protected slots:
/// Called when clicking on rename fiducial function
void renameFiducial();

protected:
QScopedPointer<qSlicerSubjectHierarchyMarkupsPluginPrivate> d_ptr;

Expand Down
10 changes: 7 additions & 3 deletions Modules/Loadable/Markups/VTKWidgets/vtkSlicerMarkupsWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ bool vtkSlicerMarkupsWidget::CanProcessInteractionEvent(vtkMRMLInteractionEventD
}

//-------------------------------------------------------------------------
bool vtkSlicerMarkupsWidget::ProcessWidgetMenu(vtkMRMLInteractionEventData* vtkNotUsed(eventData))
bool vtkSlicerMarkupsWidget::ProcessWidgetMenu(vtkMRMLInteractionEventData* eventData)
{
if (this->WidgetState != WidgetStateOnWidget || !this->MousePressedSinceMarkupPlace)
{
Expand All @@ -545,11 +545,15 @@ bool vtkSlicerMarkupsWidget::ProcessWidgetMenu(vtkMRMLInteractionEventData* vtkN
markupsNode->GetScene()->SaveStateForUndo();

vtkNew<vtkMRMLInteractionEventData> pickEventData;
pickEventData->SetType(vtkMRMLMarkupsDisplayNode::MenuEvent);
pickEventData->SetType(vtkMRMLDisplayNode::MenuEvent);
pickEventData->SetComponentType(markupsDisplayNode->GetActiveComponentType()); //TODO: This will always pass the active component for the mouse
pickEventData->SetComponentIndex(markupsDisplayNode->GetActiveComponentIndex());
pickEventData->SetViewNode(this->WidgetRep->GetViewNode());
markupsDisplayNode->InvokeEvent(vtkMRMLMarkupsDisplayNode::MenuEvent, pickEventData);
if (eventData->IsDisplayPositionValid())
{
pickEventData->SetDisplayPosition(eventData->GetDisplayPosition());
}
markupsDisplayNode->InvokeEvent(vtkMRMLDisplayNode::MenuEvent, pickEventData);
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ QList<QAction*> qSlicerSubjectHierarchyAbstractPlugin::visibilityContextMenuActi
return QList<QAction*>();
}

//-----------------------------------------------------------------------------
QList<QAction*> qSlicerSubjectHierarchyAbstractPlugin::viewContextMenuActions()const
{
return QList<QAction*>();
}

//----------------------------------------------------------------------------
double qSlicerSubjectHierarchyAbstractPlugin::canAddNodeToSubjectHierarchy(vtkMRMLNode* node,
vtkIdType parentItemID/*=vtkMRMLSubjectHierarchyNode::INVALID_ITEM_ID*/)const
Expand Down Expand Up @@ -333,6 +339,7 @@ void qSlicerSubjectHierarchyAbstractPlugin::hideAllContextMenuActions()const
allActions << this->sceneContextMenuActions();
allActions << this->itemContextMenuActions();
allActions << this->visibilityContextMenuActions();
allActions << this->viewContextMenuActions();

foreach (QAction* action, allActions)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,15 @@ class Q_SLICER_MODULE_SUBJECTHIERARCHY_WIDGETS_EXPORT qSlicerSubjectHierarchyAbs
/// \param itemID Subject Hierarchy item to show the visibility context menu items for
Q_INVOKABLE virtual void showVisibilityContextMenuActionsForItem(vtkIdType itemID) { Q_UNUSED(itemID); };

/// Get view context menu item actions that are available when right-clicking an object in the views.
/// These item context menu actions can be shown in the implementations of \sa showViewContextMenuActionsForItem
Q_INVOKABLE virtual QList<QAction*> viewContextMenuActions()const;

/// Show context menu actions valid for a given subject hierarchy item to be shown in the view.
/// \param itemID Subject Hierarchy item to show the context menu items for
/// \param eventData Supplementary data for the item that may be considered for the menu (sub-item ID, attribute, etc.)
Q_INVOKABLE virtual void showViewContextMenuActionsForItem(vtkIdType itemID, QVariantMap eventData) { Q_UNUSED(itemID); Q_UNUSED(eventData); };

// Parenting related virtual methods with default implementation
public:
/// Determines if a data node can be placed in the hierarchy using the actual plugin,
Expand Down Expand Up @@ -233,6 +242,7 @@ class Q_SLICER_MODULE_SUBJECTHIERARCHY_WIDGETS_EXPORT qSlicerSubjectHierarchyAbs
qSlicerSubjectHierarchyAbstractPlugin(const qSlicerSubjectHierarchyAbstractPlugin&); // Not implemented
void operator=(const qSlicerSubjectHierarchyAbstractPlugin&); // Not implemented
friend class qMRMLSubjectHierarchyTreeView;
friend class qSlicerSubjectHierarchyPluginLogic;
};

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ bool qSlicerSubjectHierarchyPluginHandler::registerPlugin(qSlicerSubjectHierarch
}
}

// Add view menu actions from plugin to plugin logic
foreach (QAction* action, pluginToRegister->viewContextMenuActions())
{
this->m_PluginLogic->addViewMenuAction(action);
}

// Add the plugin to the list
this->m_RegisteredPlugins << pluginToRegister;

Expand Down
Loading