/*========================================================================= Program: Visualization Toolkit Module: vtkAbstractWidget.cxx,v 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 "vtkAbstractWidget.h" #include "vtkCallbackCommand.h" #include "vtkCommand.h" #include "vtkEvent.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkWidgetCallbackMapper.h" #include "vtkWidgetEvent.h" #include "vtkWidgetEventTranslator.h" #include "vtkWidgetRepresentation.h" //------------------------------------------------------------------------------ vtkAbstractWidget::vtkAbstractWidget() { // Setup event processing this->EventCallbackCommand->SetCallback(vtkAbstractWidget::ProcessEventsHandler); // There is no parent to this widget currently this->Parent = nullptr; // Set up the geometry this->WidgetRep = nullptr; // Set priority higher than interactor styles this->Priority = 0.5; // Does this widget manage a cursor? this->ManagesCursor = 1; // Does this widget respond to interaction? this->ProcessEvents = 1; // Okay, set up the event translations for the subclasses. this->EventTranslator = vtkWidgetEventTranslator::New(); this->CallbackMapper = vtkWidgetCallbackMapper::New(); this->CallbackMapper->SetEventTranslator(this->EventTranslator); } //------------------------------------------------------------------------------ vtkAbstractWidget::~vtkAbstractWidget() { if (this->WidgetRep) { // Remove the representation from the renderer. vtkRenderer* ren = this->WidgetRep->GetRenderer(); if (ren) { ren->RemoveViewProp(this->WidgetRep); } this->WidgetRep->Delete(); this->WidgetRep = nullptr; } this->EventTranslator->Delete(); this->CallbackMapper->Delete(); this->SetEnabled(0); } //------------------------------------------------------------------------------ void vtkAbstractWidget::SetWidgetRepresentation(vtkWidgetRepresentation* r) { if (r != this->WidgetRep) { int enabled = 0; if (this->Enabled) { enabled = 1; this->SetEnabled(0); } if (this->WidgetRep) { this->WidgetRep->Delete(); } this->WidgetRep = r; if (this->WidgetRep) { this->WidgetRep->Register(this); } this->Modified(); if (enabled) { this->SetEnabled(1); } } } //------------------------------------------------------------------------------ void vtkAbstractWidget::SetEnabled(int enabling) { if (enabling) //---------------- { vtkDebugMacro(<< "Enabling widget"); if (this->Enabled) // already enabled, just return { return; } if (!this->Interactor) { vtkErrorMacro(<< "The interactor must be set prior to enabling the widget"); return; } int X = this->Interactor->GetEventPosition()[0]; int Y = this->Interactor->GetEventPosition()[1]; if (!this->CurrentRenderer) { this->SetCurrentRenderer(this->Interactor->FindPokedRenderer(X, Y)); if (this->CurrentRenderer == nullptr) { return; } } // We're ready to enable this->Enabled = 1; if (!this->WidgetRep) { this->CreateDefaultRepresentation(); } this->WidgetRep->SetRenderer(this->CurrentRenderer); this->WidgetRep->RegisterPickers(); // listen for the events found in the EventTranslator if (!this->Parent) { this->EventTranslator->AddEventsToInteractor( this->Interactor, this->EventCallbackCommand, this->Priority); } else { this->EventTranslator->AddEventsToParent( this->Parent, this->EventCallbackCommand, this->Priority); } if (this->ManagesCursor) { this->WidgetRep->ComputeInteractionState(X, Y); this->SetCursor(this->WidgetRep->GetInteractionState()); } this->WidgetRep->BuildRepresentation(); this->CurrentRenderer->AddViewProp(this->WidgetRep); this->InvokeEvent(vtkCommand::EnableEvent, nullptr); } else // disabling------------------ { vtkDebugMacro(<< "Disabling widget"); if (!this->Enabled) // already disabled, just return { return; } this->Enabled = 0; // don't listen for events any more if (!this->Parent) { this->Interactor->RemoveObserver(this->EventCallbackCommand); } else { this->Parent->RemoveObserver(this->EventCallbackCommand); } if (this->CurrentRenderer) { this->CurrentRenderer->RemoveViewProp(this->WidgetRep); } this->InvokeEvent(vtkCommand::DisableEvent, nullptr); this->SetCurrentRenderer(nullptr); if (this->WidgetRep) { this->WidgetRep->UnRegisterPickers(); } } // We no longer call render when enabled state changes. It's the applications // responsibility to explicitly call render after changing enable state. //// Should only render if there is no parent // if ( this->Interactor && !this->Parent ) // { // this->Interactor->Render(); // } } //------------------------------------------------------------------------------ void vtkAbstractWidget::ProcessEventsHandler( vtkObject* vtkNotUsed(object), unsigned long vtkEvent, void* clientdata, void* calldata) { vtkAbstractWidget* self = reinterpret_cast(clientdata); // if ProcessEvents is Off, we ignore all interaction events. if (!self->GetProcessEvents()) { return; } // if the event has data then get the translation using the // event data unsigned long widgetEvent = vtkWidgetEvent::NoEvent; if (calldata && vtkCommand::EventHasData(vtkEvent)) { widgetEvent = self->EventTranslator->GetTranslation(vtkEvent, static_cast(calldata)); } else { int modifier = vtkEvent::GetModifier(self->Interactor); // If neither the ctrl nor the shift keys are pressed, give // NoModifier a preference over AnyModifier. if (modifier == vtkEvent::AnyModifier) { widgetEvent = self->EventTranslator->GetTranslation(vtkEvent, vtkEvent::NoModifier, self->Interactor->GetKeyCode(), self->Interactor->GetRepeatCount(), self->Interactor->GetKeySym()); } if (widgetEvent == vtkWidgetEvent::NoEvent) { widgetEvent = self->EventTranslator->GetTranslation(vtkEvent, modifier, self->Interactor->GetKeyCode(), self->Interactor->GetRepeatCount(), self->Interactor->GetKeySym()); } } // Save the call data for widgets if needed self->CallData = calldata; // Invoke the widget callback if (widgetEvent != vtkWidgetEvent::NoEvent) { self->CallbackMapper->InvokeCallback(widgetEvent); } } //------------------------------------------------------------------------------ void vtkAbstractWidget::Render() { if (!this->Parent && this->Interactor) { this->Interactor->Render(); } } //------------------------------------------------------------------------------ void vtkAbstractWidget::SetPriority(float f) { if (f != this->Priority) { this->Superclass::SetPriority(f); // We are going to re-add all the events to the interactor. The // interactor observer maintains a sorted list of command-observers, sorted // by prioirty. The sorting happens only during insertion of a command- // observer into the list. Yeah.. Look at the documentation of SetPriority // in vtkInteractorObserver. That documentation recommends setting the // interactor to nullptr and back again. We won't do that because it will // cause two unnecessary re-renders, (cause we'd have had to enable and // disable the widgets). if (this->Enabled) { if (this->Interactor) { this->Interactor->RemoveObserver(this->CharObserverTag); this->Interactor->RemoveObserver(this->DeleteObserverTag); this->CharObserverTag = this->Interactor->AddObserver( vtkCommand::CharEvent, this->KeyPressCallbackCommand, this->Priority); this->DeleteObserverTag = this->Interactor->AddObserver( vtkCommand::DeleteEvent, this->KeyPressCallbackCommand, this->Priority); } if (!this->Parent) { if (this->Interactor) { this->Interactor->RemoveObserver(this->EventCallbackCommand); } } else { this->Parent->RemoveObserver(this->EventCallbackCommand); } if (!this->Parent) { if (this->Interactor) { this->EventTranslator->AddEventsToInteractor( this->Interactor, this->EventCallbackCommand, this->Priority); } } else { this->EventTranslator->AddEventsToParent( this->Parent, this->EventCallbackCommand, this->Priority); } } } } //------------------------------------------------------------------------------ void vtkAbstractWidget::PrintSelf(ostream& os, vtkIndent indent) { // Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h this->Superclass::PrintSelf(os, indent); os << indent << "ProcessEvents: " << (this->ProcessEvents ? "On" : "Off") << "\n"; if (this->WidgetRep) { os << indent << "Widget Representation: " << this->WidgetRep << "\n"; } else { os << indent << "Widget Representation: (none)\n"; } os << indent << "Manages Cursor: " << (this->ManagesCursor ? "On" : "Off") << "\n"; os << indent << "Parent: " << this->Parent << "\n"; }