You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
11 KiB
391 lines
11 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkInteractorEventRecorder.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 "vtkInteractorEventRecorder.h"
|
|
#include "vtkCallbackCommand.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkRenderWindowInteractor.h"
|
|
|
|
vtkCxxRevisionMacro(vtkInteractorEventRecorder, "$Revision: 1.8 $");
|
|
vtkStandardNewMacro(vtkInteractorEventRecorder);
|
|
|
|
float vtkInteractorEventRecorder::StreamVersion = 1.0;
|
|
|
|
vtkInteractorEventRecorder::vtkInteractorEventRecorder()
|
|
{
|
|
//take over the processing of delete and keypress events from the superclass
|
|
this->KeyPressCallbackCommand->SetCallback(
|
|
vtkInteractorEventRecorder::ProcessCharEvent);
|
|
|
|
this->Priority = VTK_LARGE_FLOAT; //get events first
|
|
this->EventCallbackCommand->SetCallback(
|
|
vtkInteractorEventRecorder::ProcessEvents);
|
|
|
|
this->FileName = NULL;
|
|
|
|
this->State = vtkInteractorEventRecorder::Start;
|
|
this->InputStream = NULL;
|
|
this->OutputStream = NULL;
|
|
|
|
this->ReadFromInputString = 0;
|
|
this->InputString = NULL;
|
|
}
|
|
|
|
vtkInteractorEventRecorder::~vtkInteractorEventRecorder()
|
|
{
|
|
this->SetInteractor(0);
|
|
|
|
if ( this->FileName )
|
|
{
|
|
delete [] this->FileName;
|
|
}
|
|
|
|
if ( this->InputStream )
|
|
{
|
|
delete this->InputStream;
|
|
this->InputStream = NULL;
|
|
}
|
|
|
|
if ( this->OutputStream )
|
|
{
|
|
delete this->OutputStream;
|
|
this->OutputStream = NULL;
|
|
}
|
|
|
|
if ( this->InputString )
|
|
{
|
|
delete [] this->InputString;
|
|
this->InputString = NULL;
|
|
}
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::SetEnabled(int enabling)
|
|
{
|
|
if ( ! this->Interactor )
|
|
{
|
|
vtkErrorMacro(<<"The interactor must be set prior to enabling/disabling widget");
|
|
return;
|
|
}
|
|
|
|
if ( enabling ) //----------------------------------------------------------
|
|
{
|
|
vtkDebugMacro(<<"Enabling widget");
|
|
|
|
if ( this->Enabled ) //already enabled, just return
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Enabled = 1;
|
|
|
|
// listen to any event
|
|
vtkRenderWindowInteractor *i = this->Interactor;
|
|
i->AddObserver(vtkCommand::AnyEvent, this->EventCallbackCommand,
|
|
this->Priority);
|
|
|
|
this->InvokeEvent(vtkCommand::EnableEvent,NULL);
|
|
}
|
|
|
|
else //disabling-----------------------------------------------------------
|
|
{
|
|
vtkDebugMacro(<<"Disabling widget");
|
|
|
|
if ( ! this->Enabled ) //already disabled, just return
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Enabled = 0;
|
|
|
|
// don't listen for events any more
|
|
this->Interactor->RemoveObserver(this->EventCallbackCommand);
|
|
|
|
this->InvokeEvent(vtkCommand::DisableEvent,NULL);
|
|
}
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::Record()
|
|
{
|
|
if ( this->State == vtkInteractorEventRecorder::Start )
|
|
{
|
|
if ( ! this->OutputStream ) //need to open file
|
|
{
|
|
this->OutputStream = new ofstream(this->FileName, ios::out);
|
|
if (this->OutputStream->fail())
|
|
{
|
|
vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
|
|
delete this->OutputStream;
|
|
return;
|
|
}
|
|
*this->OutputStream << "# StreamVersion "
|
|
<< vtkInteractorEventRecorder::StreamVersion << "\n";
|
|
}
|
|
|
|
vtkDebugMacro(<<"Recording");
|
|
this->State = vtkInteractorEventRecorder::Recording;
|
|
}
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::Play()
|
|
{
|
|
if ( this->State == vtkInteractorEventRecorder::Start )
|
|
{
|
|
if ( this->ReadFromInputString )
|
|
{
|
|
vtkDebugMacro(<< "Reading from InputString");
|
|
int len;
|
|
if ( this->InputString == NULL || (len = strlen(this->InputString) <= 0) )
|
|
{
|
|
vtkErrorMacro(<< "No input string specified");
|
|
return;
|
|
}
|
|
this->InputStream = new istrstream(this->InputString, len);
|
|
if (this->InputStream->fail())
|
|
{
|
|
vtkErrorMacro(<< "Unable to read from string");
|
|
delete this->InputStream;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ! this->InputStream ) //need to open file
|
|
{
|
|
this->InputStream = new ifstream(this->FileName, ios::in);
|
|
if (this->InputStream->fail())
|
|
{
|
|
vtkErrorMacro(<< "Unable to open file: "<< this->FileName);
|
|
delete this->InputStream;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
vtkDebugMacro(<<"Playing");
|
|
this->State = vtkInteractorEventRecorder::Playing;
|
|
|
|
// Read events and invoke them on the object in question
|
|
char event[128], keySym[64], buffer[512];
|
|
int pos[2], ctrlKey, shiftKey, keyCode, repeatCount;
|
|
float stream_version = 0.0, tempf;
|
|
|
|
while ( ! this->InputStream->eof() )
|
|
{
|
|
this->InputStream->width(256);
|
|
*this->InputStream >> event;
|
|
|
|
// Quick skip comment
|
|
if (*event == '#')
|
|
{
|
|
this->InputStream->getline(buffer, 512);
|
|
|
|
// Parse the StreamVersion (not using >> since comment could be empty)
|
|
// Expecting: # StreamVersion x.y
|
|
|
|
if (strlen(buffer) > 15 && !strncmp(buffer, " StreamVersion ", 15))
|
|
{
|
|
int res = sscanf(buffer + 15, "%f", &tempf);
|
|
if (res && res != EOF)
|
|
{
|
|
stream_version = tempf;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned long ievent = vtkCommand::GetEventIdFromString(event);
|
|
if (ievent == vtkCommand::NoEvent)
|
|
{
|
|
this->InputStream->ignore(512, '\n');
|
|
}
|
|
else
|
|
{
|
|
if (stream_version >= 1.1)
|
|
{
|
|
// We could grab the time info here
|
|
}
|
|
*this->InputStream >> pos[0];
|
|
*this->InputStream >> pos[1];
|
|
*this->InputStream >> ctrlKey;
|
|
*this->InputStream >> shiftKey;
|
|
*this->InputStream >> keyCode;
|
|
*this->InputStream >> repeatCount;
|
|
*this->InputStream >> keySym;
|
|
|
|
this->Interactor->SetEventPosition(pos);
|
|
this->Interactor->SetControlKey(ctrlKey);
|
|
this->Interactor->SetShiftKey(shiftKey);
|
|
this->Interactor->SetKeyCode(keyCode);
|
|
this->Interactor->SetRepeatCount(repeatCount);
|
|
this->Interactor->SetKeySym(keySym);
|
|
|
|
this->Interactor->InvokeEvent(ievent, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this->State = vtkInteractorEventRecorder::Start;
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::Stop()
|
|
{
|
|
this->State = vtkInteractorEventRecorder::Start;
|
|
this->Modified();
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::Rewind()
|
|
{
|
|
if ( ! this->InputStream ) //need to already have an open file
|
|
{
|
|
vtkGenericWarningMacro(<<"No input file opened to rewind...");
|
|
}
|
|
this->InputStream->clear();
|
|
this->InputStream->seekg(0);
|
|
}
|
|
|
|
// This adds the keypress event observer and the delete event observer
|
|
void vtkInteractorEventRecorder::SetInteractor(vtkRenderWindowInteractor* i)
|
|
{
|
|
if (i == this->Interactor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if we already have an Interactor then stop observing it
|
|
if (this->Interactor)
|
|
{
|
|
this->SetEnabled(0); //disable the old interactor
|
|
this->Interactor->RemoveObserver(this->KeyPressCallbackCommand);
|
|
}
|
|
|
|
this->Interactor = i;
|
|
|
|
// add observers for each of the events handled in ProcessEvents
|
|
if (i)
|
|
{
|
|
i->AddObserver(vtkCommand::CharEvent,
|
|
this->KeyPressCallbackCommand, this->Priority);
|
|
i->AddObserver(vtkCommand::DeleteEvent,
|
|
this->KeyPressCallbackCommand, this->Priority);
|
|
}
|
|
|
|
this->Modified();
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::ProcessCharEvent(vtkObject* object,
|
|
unsigned long event,
|
|
void* clientData,
|
|
void* vtkNotUsed(callData))
|
|
{
|
|
vtkInteractorEventRecorder* self =
|
|
reinterpret_cast<vtkInteractorEventRecorder *>( clientData );
|
|
vtkRenderWindowInteractor* rwi =
|
|
static_cast<vtkRenderWindowInteractor *>( object );
|
|
|
|
switch(event)
|
|
{
|
|
case vtkCommand::DeleteEvent:
|
|
// if the interactor is being deleted then remove the event handlers
|
|
self->SetInteractor(0);
|
|
break;
|
|
|
|
case vtkCommand::CharEvent:
|
|
if ( self->KeyPressActivation )
|
|
{
|
|
if (rwi->GetKeyCode() == self->KeyPressActivationValue )
|
|
{
|
|
if ( !self->Enabled )
|
|
{
|
|
self->On();
|
|
}
|
|
else
|
|
{
|
|
self->Off();
|
|
}
|
|
}//event not aborted
|
|
}//if activation enabled
|
|
}
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::ProcessEvents(vtkObject* object,
|
|
unsigned long event,
|
|
void* clientData,
|
|
void* vtkNotUsed(callData))
|
|
{
|
|
vtkInteractorEventRecorder* self =
|
|
reinterpret_cast<vtkInteractorEventRecorder *>( clientData );
|
|
vtkRenderWindowInteractor* rwi =
|
|
static_cast<vtkRenderWindowInteractor *>( object );
|
|
|
|
// all events are processed
|
|
if ( self->State == vtkInteractorEventRecorder::Recording )
|
|
{
|
|
switch(event)
|
|
{
|
|
case vtkCommand::ModifiedEvent: //dont want these
|
|
break;
|
|
|
|
default:
|
|
self->WriteEvent(vtkCommand::GetStringFromEventId(event),
|
|
rwi->GetEventPosition(), rwi->GetControlKey(),
|
|
rwi->GetShiftKey(), rwi->GetKeyCode(),
|
|
rwi->GetRepeatCount(), rwi->GetKeySym());
|
|
}
|
|
self->OutputStream->flush();
|
|
}
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::WriteEvent(const char* event, int pos[2],
|
|
int ctrlKey, int shiftKey,
|
|
int keyCode, int repeatCount,
|
|
char* keySym)
|
|
{
|
|
*this->OutputStream << event << " " << pos[0] << " " << pos[1] << " "
|
|
<< ctrlKey << " " << shiftKey << " "
|
|
<< keyCode << " " << repeatCount << " "
|
|
<< keySym << "\n";
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::ReadEvent()
|
|
{
|
|
}
|
|
|
|
void vtkInteractorEventRecorder::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
if (this->FileName)
|
|
{
|
|
os << indent << "File Name: " << this->FileName << "\n";
|
|
}
|
|
|
|
os << indent << "ReadFromInputString: "
|
|
<< (this->ReadFromInputString ? "On\n" : "Off\n");
|
|
|
|
if ( this->InputString )
|
|
{
|
|
os << indent << "Input String: " << this->InputString << "\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Input String: (None)\n";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|