Commit 408a876e authored by Ken Martin's avatar Ken Martin

add vtkEventData class and support

This topic introduces support for events in VTK to pass a
vtkEventData instance as their calldata. This instance can
be used to hold event specific data that would otherwise
complicate the render window interactor. The event specific
data also allows us to have fewer vtkCommands as we do not
need a specific command for each button on a controller but
rather can include the controller button as data in the
appropriate vtkEventData subclass.

Currently this is only implemented for 3D events but it could
be updated to handle mouse, keyboard or events as desired.
parent 1fd82d5d
......@@ -80,7 +80,14 @@ unsigned long vtkCommand::GetEventIdFromString(const char *event)
return vtkCommand::NoEvent;
}
bool vtkCommand::EventHasData(unsigned long event)
{
switch (event)
{
case vtkCommand::Button3DEvent:
case vtkCommand::Move3DEvent:
return true;
default:
return false;
}
}
......@@ -340,7 +340,9 @@
_vtk_add_event(FourthButtonPressEvent)\
_vtk_add_event(FourthButtonReleaseEvent)\
_vtk_add_event(FifthButtonPressEvent)\
_vtk_add_event(FifthButtonReleaseEvent)
_vtk_add_event(FifthButtonReleaseEvent)\
_vtk_add_event(Move3DEvent)\
_vtk_add_event(Button3DEvent)
#define vtkEventDeclarationMacro(_enum_name)\
enum _enum_name{\
......@@ -389,6 +391,11 @@ public:
static unsigned long GetEventIdFromString(const char *event);
//@}
/**
* Does this event type contain vtkEventData
*/
static bool EventHasData(unsigned long event);
/**
* Set/Get the abort flag. If this is set to true no further
* commands are executed.
......
/*=========================================================================
Program: Visualization Toolkit
Module: vtkEventData.h
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.
=========================================================================*/
/**
* @brief platform-independent event data structures
*/
#ifndef vtkEventData_h
#define vtkEventData_h
#include "vtkCommand.h"
// enumeration of possible devices
enum class vtkEventDataDevice {
Unknown = -1,
HeadMountedDisplay,
RightController,
LeftController,
NumberOfDevices
};
const int vtkEventDataNumberOfDevices =
static_cast<int>(vtkEventDataDevice::NumberOfDevices);
// enumeration of possible device inputs
enum class vtkEventDataDeviceInput {
Unknown = -1,
Trigger,
TrackPad,
Grip,
ApplicationMenu,
NumberOfInputs
};
const int vtkEventDataNumberOfInputs =
static_cast<int>(vtkEventDataDeviceInput::NumberOfInputs);
// enumeration of actions that can happen
enum class vtkEventDataAction {
Unknown = -1,
Press,
Release,
NumberOfActions
};
class vtkEventDataForDevice;
class vtkEventDataDevice3D;
class vtkEventData : public vtkObjectBase
{
public:
vtkBaseTypeMacro(vtkEventData,vtkObjectBase);
int GetType() const { return this->Type; }
// are two events equivalent
bool operator==(const vtkEventData& a) const
{
return this->Type == a.Type && this->Equivalent(&a);
}
// some convenience downcasts
virtual vtkEventDataForDevice *GetAsEventDataForDevice() { return nullptr; }
virtual vtkEventDataDevice3D *GetAsEventDataDevice3D() { return nullptr; }
protected:
vtkEventData() {};
~vtkEventData() VTK_OVERRIDE {}
// subclasses override this to define their
// definition of equivalent
virtual bool Equivalent(const vtkEventData *ed) const = 0;
int Type;
private:
vtkEventData(const vtkEventData& c) VTK_DELETE_FUNCTION;
};
// a subclass for events that may have one or more of
// device, input, and action
class vtkEventDataForDevice : public vtkEventData
{
public:
vtkTypeMacro(vtkEventDataForDevice,vtkEventData);
vtkEventDataDevice GetDevice() const { return this->Device; }
vtkEventDataDeviceInput GetInput() const { return this->Input; }
vtkEventDataAction GetAction() const { return this->Action; }
void SetDevice(vtkEventDataDevice v) { this->Device = v; }
void SetInput(vtkEventDataDeviceInput v) { this->Input = v; }
void SetAction(vtkEventDataAction v) { this->Action = v; }
vtkEventDataForDevice *GetAsEventDataForDevice() VTK_OVERRIDE { return this; }
protected:
vtkEventDataDevice Device;
vtkEventDataDeviceInput Input;
vtkEventDataAction Action;
bool Equivalent(const vtkEventData *e) const VTK_OVERRIDE {
const vtkEventDataForDevice *edd = static_cast<const vtkEventDataForDevice *>(e);
return this->Device == edd->Device && this->Input == edd->Input && this->Action == edd->Action;
};
vtkEventDataForDevice() {
this->Device = vtkEventDataDevice::Unknown;
this->Input = vtkEventDataDeviceInput::Unknown;
this->Action = vtkEventDataAction::Unknown; }
~vtkEventDataForDevice() VTK_OVERRIDE {}
private:
vtkEventDataForDevice(const vtkEventData& c) VTK_DELETE_FUNCTION;
void operator=(const vtkEventDataForDevice&) VTK_DELETE_FUNCTION;
};
// a subclass for events that have a 3D world position
// direction and orientation.
class vtkEventDataDevice3D : public vtkEventDataForDevice
{
public:
vtkTypeMacro(vtkEventDataDevice3D,vtkEventDataForDevice);
vtkEventDataDevice3D *GetAsEventDataDevice3D() VTK_OVERRIDE { return this; }
void GetWorldPosition(double v[3]) const {
std::copy(this->WorldPosition, this->WorldPosition + 3, v);
}
const double *GetWorldPosition() const {
return this->WorldPosition;
}
void SetWorldPosition(const double p[3])
{
this->WorldPosition[0] = p[0];
this->WorldPosition[1] = p[1];
this->WorldPosition[2] = p[2];
}
void GetWorldDirection(double v[3]) const {
std::copy(this->WorldDirection, this->WorldDirection + 3, v);
}
const double *GetWorldDirection() const {
return this->WorldDirection;
}
void SetWorldDirection(const double p[3])
{
this->WorldDirection[0] = p[0];
this->WorldDirection[1] = p[1];
this->WorldDirection[2] = p[2];
}
void GetWorldOrientation(double v[4]) const {
std::copy(this->WorldOrientation, this->WorldOrientation + 4, v);
}
const double *GetWorldOrientation() const {
return this->WorldOrientation;
}
void SetWorldOrientation(const double p[4])
{
this->WorldOrientation[0] = p[0];
this->WorldOrientation[1] = p[1];
this->WorldOrientation[2] = p[2];
this->WorldOrientation[3] = p[3];
}
protected:
double WorldPosition[3];
double WorldOrientation[4];
double WorldDirection[3];
vtkEventDataDevice3D() {}
~vtkEventDataDevice3D() VTK_OVERRIDE {}
private:
vtkEventDataDevice3D(const vtkEventDataDevice3D& c) VTK_DELETE_FUNCTION;
void operator=(const vtkEventDataDevice3D&) VTK_DELETE_FUNCTION;
};
// subclass for button event 3d
class vtkEventDataButton3D : public vtkEventDataDevice3D
{
public:
vtkTypeMacro(vtkEventDataButton3D, vtkEventDataDevice3D);
static vtkEventDataButton3D *New()
{return new vtkEventDataButton3D;};
protected:
vtkEventDataButton3D() { this->Type = vtkCommand::Button3DEvent; }
~vtkEventDataButton3D() VTK_OVERRIDE {}
private:
vtkEventDataButton3D(const vtkEventDataButton3D& c) VTK_DELETE_FUNCTION;
void operator=(const vtkEventDataButton3D&) VTK_DELETE_FUNCTION;
};
// subclass for move event 3d
class vtkEventDataMove3D : public vtkEventDataDevice3D
{
public:
vtkTypeMacro(vtkEventDataMove3D, vtkEventDataDevice3D);
static vtkEventDataMove3D *New()
{return new vtkEventDataMove3D;};
protected:
vtkEventDataMove3D() { this->Type = vtkCommand::Move3DEvent; }
~vtkEventDataMove3D() VTK_OVERRIDE {}
private:
vtkEventDataMove3D(const vtkEventDataMove3D& c) VTK_DELETE_FUNCTION;
void operator=(const vtkEventDataMove3D&) VTK_DELETE_FUNCTION;
};
#endif
// VTK-HeaderTest-Exclude: vtkEventData.h
......@@ -23,8 +23,6 @@
#include "vtkEvent.h"
#include "vtkWidgetEvent.h"
//----------------------------------------------------------------------
vtkAbstractWidget::vtkAbstractWidget()
{
......@@ -215,27 +213,37 @@ void vtkAbstractWidget::ProcessEventsHandler(vtkObject* vtkNotUsed(object),
return;
}
int modifier = vtkEvent::GetModifier(self->Interactor);
// if the event has data then get the translation using the
// event data
unsigned long widgetEvent = vtkWidgetEvent::NoEvent;
// If neither the ctrl nor the shift keys are pressed, give
// NoModifier a preference over AnyModifer.
if (modifier == vtkEvent::AnyModifier)
if (calldata && vtkCommand::EventHasData(vtkEvent))
{
widgetEvent = self->EventTranslator->GetTranslation(vtkEvent,
vtkEvent::NoModifier,
static_cast<vtkEventData *>(calldata));
}
else
{
int modifier = vtkEvent::GetModifier(self->Interactor);
// If neither the ctrl nor the shift keys are pressed, give
// NoModifier a preference over AnyModifer.
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());
}
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
......
......@@ -103,6 +103,15 @@ void vtkWidgetCallbackMapper::SetCallbackMethod(unsigned long VTKEvent,
this->SetCallbackMethod(widgetEvent,w,f);
}
//----------------------------------------------------------------------------
void vtkWidgetCallbackMapper::SetCallbackMethod(unsigned long VTKEvent,
vtkEventData *edata,
unsigned long widgetEvent,
vtkAbstractWidget *w, CallbackType f)
{
this->EventTranslator->SetTranslation(VTKEvent, edata, widgetEvent);
this->SetCallbackMethod(widgetEvent,w,f);
}
//----------------------------------------------------------------------------
void vtkWidgetCallbackMapper::SetCallbackMethod(unsigned long widgetEvent,
......
......@@ -36,7 +36,7 @@ class vtkWidgetEvent;
class vtkAbstractWidget;
class vtkWidgetEventTranslator;
class vtkCallbackMap; // PIMPL encapsulation of STL map
class vtkEventData;
class VTKINTERACTIONWIDGETS_EXPORT vtkWidgetCallbackMapper : public vtkObject
{
......@@ -84,6 +84,9 @@ public:
int repeatCount, const char* keySym,
unsigned long widgetEvent,
vtkAbstractWidget *w, CallbackType f);
void SetCallbackMethod(unsigned long VTKEvent, vtkEventData *ed,
unsigned long widgetEvent,
vtkAbstractWidget *w, CallbackType f);
//void SetCallbackMethod(vtkWidgetEvent *vtkEvent, unsigned long widgetEvent,
// vtkAbstractWidget *w, CallbackType f);
//@}
......
......@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkWidgetEventTranslator.h"
#include "vtkCommand.h"
#include "vtkEventData.h"
#include "vtkObjectFactory.h"
#include "vtkWidgetEvent.h"
#include "vtkRenderWindowInteractor.h"
......@@ -31,12 +32,37 @@ vtkStandardNewMacro(vtkWidgetEventTranslator);
struct EventItem {
vtkSmartPointer< vtkEvent > VTKEvent;
unsigned long WidgetEvent;
vtkEventData *EventData = nullptr;
bool HasData = false;
EventItem(vtkEvent *e, unsigned long we)
{
this->VTKEvent = e;
this->WidgetEvent = we;
this->HasData = false;
}
EventItem(vtkEventData *edata, unsigned long we)
{
this->EventData = edata;
this->EventData->Register(nullptr);
this->WidgetEvent = we;
this->HasData = true;
}
~EventItem() { if (this->HasData && this->EventData) { this->EventData->UnRegister(nullptr); this->EventData = nullptr; }}
EventItem(const EventItem&v) {
this->VTKEvent = v.VTKEvent;
this->WidgetEvent = v.WidgetEvent;
this->HasData = v.HasData;
this->EventData = v.EventData;
if (this->HasData && this->EventData)
{
this->EventData->Register(nullptr);
}
}
private:
EventItem() VTK_DELETE_FUNCTION;
};
// A list of events
......@@ -68,6 +94,19 @@ struct EventList : public std::list<EventItem>
return vtkWidgetEvent::NoEvent;
}
unsigned long find(vtkEventData *edata)
{
std::list<EventItem>::iterator liter = this->begin();
for ( ; liter != this->end(); ++liter)
{
if ( liter->HasData && *edata == *liter->EventData )
{
return liter->WidgetEvent;
}
}
return vtkWidgetEvent::NoEvent;
}
// Remove a mapping
int Remove( vtkEvent *VTKEvent )
{
......@@ -82,10 +121,21 @@ struct EventList : public std::list<EventItem>
}
return 0;
}
int Remove( vtkEventData *edata )
{
std::list<EventItem>::iterator liter = this->begin();
for ( ; liter != this->end(); ++liter)
{
if ( liter->HasData && *edata == *liter->EventData )
{
this->erase( liter );
return 1;
}
}
return 0;
}
};
// A STL map used to translate VTK events into lists of events. The reason
// that we have this list is because of the modifiers on the event. The
// VTK event id maps to the list, and then comparisons are done to
......@@ -153,6 +203,21 @@ void vtkWidgetEventTranslator::SetTranslation(unsigned long VTKEvent,
}
}
void vtkWidgetEventTranslator::SetTranslation(
unsigned long VTKEvent,
vtkEventData *edata,
unsigned long widgetEvent)
{
if (widgetEvent != vtkWidgetEvent::NoEvent)
{
(*this->EventMap)[VTKEvent].push_back(EventItem(edata,widgetEvent));
}
else
{
this->RemoveTranslation( edata );
}
}
//----------------------------------------------------------------------------
void vtkWidgetEventTranslator::SetTranslation(vtkEvent *VTKEvent,
unsigned long widgetEvent)
......@@ -207,10 +272,21 @@ unsigned long vtkWidgetEventTranslator::GetTranslation(unsigned long VTKEvent,
EventList &elist = (*iter).second;
return elist.find(this->Event);
}
else
return vtkWidgetEvent::NoEvent;
}
//----------------------------------------------------------------------------
unsigned long vtkWidgetEventTranslator::GetTranslation(
unsigned long ,
vtkEventData *edata )
{
EventMapIterator iter = this->EventMap->find(edata->GetType());
if (iter != this->EventMap->end())
{
return vtkWidgetEvent::NoEvent;
EventList &elist = (*iter).second;
return elist.find(edata);
}
return vtkWidgetEvent::NoEvent;
}
//----------------------------------------------------------------------------
......@@ -263,6 +339,27 @@ int vtkWidgetEventTranslator::RemoveTranslation( vtkEvent *e )
return numTranslationsRemoved;
}
//----------------------------------------------------------------------------
int vtkWidgetEventTranslator::RemoveTranslation( vtkEventData *edata )
{
EventMapIterator iter = this->EventMap->find(edata->GetType());
int numTranslationsRemoved = 0;
if (iter != this->EventMap->end())
{
while (iter->second.Remove(edata))
{
++numTranslationsRemoved;
iter = this->EventMap->find(edata->GetType());
if (iter == this->EventMap->end())
{
break;
}
}
}
return numTranslationsRemoved;
}
//----------------------------------------------------------------------------
int vtkWidgetEventTranslator::RemoveTranslation(unsigned long VTKEvent)
{
......
......@@ -42,7 +42,7 @@ class vtkRenderWindowInteractor;
class vtkCallbackCommand;
class vtkEvent;
class vtkAbstractWidget;
class vtkEventData;
// This is a lightweight class that should be used internally by the widgets
class VTKINTERACTIONWIDGETS_EXPORT vtkWidgetEventTranslator : public vtkObject
......@@ -72,6 +72,7 @@ public:
void SetTranslation(unsigned long VTKEvent, int modifier, char keyCode,
int repeatCount, const char* keySym, unsigned long widgetEvent);
void SetTranslation(vtkEvent *VTKevent, unsigned long widgetEvent);
void SetTranslation(unsigned long VTKEvent, vtkEventData *edata, unsigned long widgetEvent);
//@}
//@{
......@@ -83,6 +84,7 @@ public:
const char *GetTranslation(const char *VTKEvent);
unsigned long GetTranslation(unsigned long VTKEvent, int modifier, char keyCode,
int repeatCount, char* keySym);
unsigned long GetTranslation(unsigned long VTKEvent, vtkEventData *edata);
unsigned long GetTranslation(vtkEvent *VTKEvent);
//@}
......@@ -95,6 +97,7 @@ public:
int modifier, char keyCode,
int repeatCount, char* keySym);
int RemoveTranslation( vtkEvent *e );
int RemoveTranslation( vtkEventData *e );
int RemoveTranslation(unsigned long VTKEvent);
int RemoveTranslation(const char *VTKEvent);
//@}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment