/*========================================================================= Program: Visualization Toolkit Module: vtkResliceCursorWidget.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ #include "vtkResliceCursorWidget.h" #include "vtkCallbackCommand.h" #include "vtkCommand.h" #include "vtkEvent.h" #include "vtkImageData.h" #include "vtkImageMapToWindowLevelColors.h" #include "vtkInteractorStyleImage.h" #include "vtkObjectFactory.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkResliceCursor.h" #include "vtkResliceCursorLineRepresentation.h" #include "vtkWidgetCallbackMapper.h" #include "vtkWidgetEvent.h" #include "vtkWidgetEventTranslator.h" vtkStandardNewMacro(vtkResliceCursorWidget); //------------------------------------------------------------------------------ vtkResliceCursorWidget::vtkResliceCursorWidget() { // Set the initial state this->WidgetState = vtkResliceCursorWidget::Start; this->ModifierActive = 0; // Okay, define the events for this widget this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkEvent::NoModifier, 0, 0, nullptr, vtkWidgetEvent::Select, this, vtkResliceCursorWidget::SelectAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkEvent::ControlModifier, 0, 0, nullptr, vtkWidgetEvent::Rotate, this, vtkResliceCursorWidget::RotateAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent, vtkWidgetEvent::EndSelect, this, vtkResliceCursorWidget::EndSelectAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonPressEvent, vtkWidgetEvent::Resize, this, vtkResliceCursorWidget::ResizeThicknessAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonReleaseEvent, vtkWidgetEvent::EndResize, this, vtkResliceCursorWidget::EndSelectAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent, vtkEvent::AltModifier, 0, 0, nullptr, vtkWidgetEvent::Translate, this, vtkResliceCursorWidget::TranslateAction); this->CallbackMapper->SetCallbackMethod( vtkCommand::MouseMoveEvent, vtkWidgetEvent::Move, this, vtkResliceCursorWidget::MoveAction); this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent, vtkEvent::NoModifier, 111, 1, "o", vtkWidgetEvent::Reset, this, vtkResliceCursorWidget::ResetResliceCursorAction); this->ManageWindowLevel = 1; } //------------------------------------------------------------------------------ vtkResliceCursorWidget::~vtkResliceCursorWidget() = default; //------------------------------------------------------------------------------ void vtkResliceCursorWidget::SetEnabled(int enabling) { this->Superclass::SetEnabled(enabling); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::CreateDefaultRepresentation() { if (!this->WidgetRep) { this->WidgetRep = vtkResliceCursorLineRepresentation::New(); } } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::SetCursor(int cState) { if (!this->ManagesCursor) { return; } switch (cState) { case vtkResliceCursorRepresentation::OnAxis1: case vtkResliceCursorRepresentation::OnAxis2: this->RequestCursorShape(VTK_CURSOR_HAND); break; case vtkResliceCursorRepresentation::OnCenter: if (vtkEvent::GetModifier(this->Interactor) != vtkEvent::ControlModifier) { this->RequestCursorShape(VTK_CURSOR_SIZEALL); } break; case vtkResliceCursorRepresentation::Outside: default: this->RequestCursorShape(VTK_CURSOR_DEFAULT); } } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::ResizeThicknessAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = reinterpret_cast(w); vtkResliceCursorRepresentation* rep = reinterpret_cast(self->WidgetRep); int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; rep->ComputeInteractionState(X, Y, self->ModifierActive); if (self->WidgetRep->GetInteractionState() == vtkResliceCursorRepresentation::Outside || rep->GetResliceCursor()->GetThickMode() == 0) { return; } rep->SetManipulationMode(vtkResliceCursorRepresentation::ResizeThickness); self->GrabFocus(self->EventCallbackCommand); double eventPos[2]; eventPos[0] = static_cast(X); eventPos[1] = static_cast(Y); self->WidgetRep->StartWidgetInteraction(eventPos); // We are definitely selected self->WidgetState = vtkResliceCursorWidget::Active; self->SetCursor(self->WidgetRep->GetInteractionState()); // Highlight as necessary self->WidgetRep->Highlight(1); self->EventCallbackCommand->SetAbortFlag(1); self->StartInteraction(); self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); self->Render(); self->InvokeAnEvent(); // Show the thickness in "mm" rep->ActivateText(1); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::EndResizeThicknessAction(vtkAbstractWidget*) {} //------------------------------------------------------------------------------ void vtkResliceCursorWidget::SelectAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = reinterpret_cast(w); vtkResliceCursorRepresentation* rep = reinterpret_cast(self->WidgetRep); int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; self->ModifierActive = vtkEvent::GetModifier(self->Interactor); rep->ComputeInteractionState(X, Y, self->ModifierActive); if (self->WidgetRep->GetInteractionState() == vtkResliceCursorRepresentation::Outside) { if (self->GetManageWindowLevel() && rep->GetShowReslicedImage()) { self->StartWindowLevel(); } else { rep->SetManipulationMode(vtkResliceCursorRepresentation::None); return; } } else { rep->SetManipulationMode(vtkResliceCursorRepresentation::PanAndRotate); } if (rep->GetManipulationMode() == vtkResliceCursorRepresentation::None) { return; } self->GrabFocus(self->EventCallbackCommand); double eventPos[2]; eventPos[0] = static_cast(X); eventPos[1] = static_cast(Y); self->WidgetRep->StartWidgetInteraction(eventPos); // We are definitely selected self->WidgetState = vtkResliceCursorWidget::Active; self->SetCursor(self->WidgetRep->GetInteractionState()); // Highlight as necessary self->WidgetRep->Highlight(1); self->EventCallbackCommand->SetAbortFlag(1); self->StartInteraction(); self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); self->Render(); self->InvokeAnEvent(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::RotateAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = reinterpret_cast(w); vtkResliceCursorRepresentation* rep = reinterpret_cast(self->WidgetRep); int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; self->ModifierActive = vtkEvent::GetModifier(self->Interactor); rep->ComputeInteractionState(X, Y, self->ModifierActive); if (self->WidgetRep->GetInteractionState() == vtkResliceCursorRepresentation::Outside) { return; } rep->SetManipulationMode(vtkResliceCursorRepresentation::RotateBothAxes); self->GrabFocus(self->EventCallbackCommand); double eventPos[2]; eventPos[0] = static_cast(X); eventPos[1] = static_cast(Y); self->WidgetRep->StartWidgetInteraction(eventPos); // We are definitely selected self->WidgetState = vtkResliceCursorWidget::Active; self->SetCursor(self->WidgetRep->GetInteractionState()); // Highlight as necessary self->WidgetRep->Highlight(1); self->EventCallbackCommand->SetAbortFlag(1); self->StartInteraction(); self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); self->Render(); self->InvokeAnEvent(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::TranslateAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = vtkResliceCursorWidget::SafeDownCast(w); vtkResliceCursorLineRepresentation* rep = vtkResliceCursorLineRepresentation::SafeDownCast(self->WidgetRep); int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; self->ModifierActive = vtkEvent::GetModifier(self->Interactor); rep->ComputeInteractionState(X, Y, self->ModifierActive); if (self->WidgetRep->GetInteractionState() == vtkResliceCursorRepresentation::Outside) { return; } rep->SetManipulationMode(vtkResliceCursorRepresentation::TranslateSingleAxis); self->GrabFocus(self->EventCallbackCommand); double eventPos[2]; eventPos[0] = static_cast(X); eventPos[1] = static_cast(Y); self->WidgetRep->StartWidgetInteraction(eventPos); // We are definitely selected self->WidgetState = vtkResliceCursorWidget::Active; self->SetCursor(self->WidgetRep->GetInteractionState()); // Highlight as necessary self->WidgetRep->Highlight(1); self->EventCallbackCommand->SetAbortFlag(1); self->StartInteraction(); self->InvokeEvent(vtkCommand::StartInteractionEvent, nullptr); self->Render(); self->InvokeAnEvent(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::MoveAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = reinterpret_cast(w); vtkResliceCursorRepresentation* rep = reinterpret_cast(self->WidgetRep); // compute some info we need for all cases int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; // Set the cursor appropriately if (self->WidgetState == vtkResliceCursorWidget::Start) { self->ModifierActive = vtkEvent::GetModifier(self->Interactor); int state = self->WidgetRep->GetInteractionState(); rep->ComputeInteractionState(X, Y, self->ModifierActive); self->SetCursor(self->WidgetRep->GetInteractionState()); if (state != self->WidgetRep->GetInteractionState()) { self->Render(); } return; } // Okay, adjust the representation double eventPosition[2]; eventPosition[0] = static_cast(X); eventPosition[1] = static_cast(Y); self->WidgetRep->WidgetInteraction(eventPosition); // Got this event, we are finished self->EventCallbackCommand->SetAbortFlag(1); self->InvokeEvent(vtkCommand::InteractionEvent, nullptr); self->Render(); self->InvokeAnEvent(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::EndSelectAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = static_cast(w); vtkResliceCursorRepresentation* rep = reinterpret_cast(self->WidgetRep); if (self->WidgetState != vtkResliceCursorWidget::Active) { return; } int X = self->Interactor->GetEventPosition()[0]; int Y = self->Interactor->GetEventPosition()[1]; double eventPos[2]; eventPos[0] = static_cast(X); eventPos[1] = static_cast(Y); self->WidgetRep->EndWidgetInteraction(eventPos); // return to initial state self->WidgetState = vtkResliceCursorWidget::Start; self->ModifierActive = 0; // Highlight as necessary self->WidgetRep->Highlight(0); // Remove any text displays. We are no longer active. rep->ActivateText(0); // stop adjusting self->ReleaseFocus(); self->EventCallbackCommand->SetAbortFlag(1); self->EndInteraction(); self->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr); self->WidgetState = vtkResliceCursorWidget::Start; rep->SetManipulationMode(vtkResliceCursorRepresentation::None); self->Render(); self->InvokeAnEvent(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::ResetResliceCursorAction(vtkAbstractWidget* w) { vtkResliceCursorWidget* self = reinterpret_cast(w); self->ResetResliceCursor(); // Render in response to changes self->Render(); // Invoke a reslice cursor event self->InvokeEvent(vtkResliceCursorWidget::ResetCursorEvent, nullptr); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::ResetResliceCursor() { vtkResliceCursorRepresentation* rep = reinterpret_cast(this->WidgetRep); if (!rep->GetResliceCursor()) { return; // nothing to reset } // Reset the reslice cursor rep->GetResliceCursor()->Reset(); rep->InitializeReslicePlane(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::StartWindowLevel() { vtkResliceCursorRepresentation* rep = reinterpret_cast(this->WidgetRep); int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; // Okay, make sure that the pick is in the current renderer if (!this->CurrentRenderer || !this->CurrentRenderer->IsInViewport(X, Y)) { rep->SetManipulationMode(vtkResliceCursorRepresentation::None); return; } rep->SetManipulationMode(vtkResliceCursorRepresentation::WindowLevelling); rep->ActivateText(1); rep->ManageTextDisplay(); } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::InvokeAnEvent() { // We invoke the appropriate event. In cases where the cursor is moved // around, or rotated, also have the reslice cursor invoke an event. vtkResliceCursorRepresentation* rep = reinterpret_cast(this->WidgetRep); if (rep) { int mode = rep->GetManipulationMode(); if (mode == vtkResliceCursorRepresentation::WindowLevelling) { this->InvokeEvent(WindowLevelEvent, nullptr); } else if (mode == vtkResliceCursorRepresentation::PanAndRotate) { this->InvokeEvent(ResliceAxesChangedEvent, nullptr); rep->GetResliceCursor()->InvokeEvent(ResliceAxesChangedEvent, nullptr); } else if (mode == vtkResliceCursorRepresentation::RotateBothAxes) { this->InvokeEvent(ResliceAxesChangedEvent, nullptr); rep->GetResliceCursor()->InvokeEvent(ResliceAxesChangedEvent, nullptr); } else if (mode == vtkResliceCursorRepresentation::TranslateSingleAxis) { this->InvokeEvent(ResliceAxesChangedEvent, nullptr); rep->GetResliceCursor()->InvokeEvent(ResliceAxesChangedEvent, nullptr); } else if (mode == vtkResliceCursorRepresentation::ResizeThickness) { this->InvokeEvent(ResliceThicknessChangedEvent, nullptr); rep->GetResliceCursor()->InvokeEvent(ResliceAxesChangedEvent, nullptr); } } } //------------------------------------------------------------------------------ void vtkResliceCursorWidget::PrintSelf(ostream& os, vtkIndent indent) { // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h this->Superclass::PrintSelf(os, indent); os << indent << "ManageWindowLevel: " << this->ManageWindowLevel << endl; // this->ModifierActive; // this->WidgetState; }