vtkInteractorEventRecorder.cxx 12.5 KB
Newer Older
1
2
3
4
5
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkInteractorEventRecorder.cxx

Brad King's avatar
Brad King committed
6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7
8
9
10
11
12
13
14
15
16
17
18
19
  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"

20
#include <vtksys/ios/sstream>
21
#include <locale>
22
#include <vtksys/SystemTools.hxx>
23

24
25
vtkStandardNewMacro(vtkInteractorEventRecorder);

26
float vtkInteractorEventRecorder::StreamVersion = 1.0f;
27

28
//----------------------------------------------------------------------------
29
30
vtkInteractorEventRecorder::vtkInteractorEventRecorder()
{
Will Schroeder's avatar
Will Schroeder committed
31
  //take over the processing of delete and keypress events from the superclass
32
33
  this->KeyPressCallbackCommand->SetCallback(
    vtkInteractorEventRecorder::ProcessCharEvent);
34
  this->KeyPressCallbackCommand->SetPassiveObserver(1); // get events first
35
36
37

  this->EventCallbackCommand->SetCallback(
    vtkInteractorEventRecorder::ProcessEvents);
38
  this->EventCallbackCommand->SetPassiveObserver(1); // get events first
39

Will Schroeder's avatar
Will Schroeder committed
40
  this->FileName = NULL;
41
42
43
44
45

  this->State = vtkInteractorEventRecorder::Start;
  this->InputStream = NULL;
  this->OutputStream = NULL;

Will Schroeder's avatar
Will Schroeder committed
46
47
  this->ReadFromInputString = 0;
  this->InputString = NULL;
48
49
}

50
//----------------------------------------------------------------------------
51
52
vtkInteractorEventRecorder::~vtkInteractorEventRecorder()
{
Ken Martin's avatar
Ken Martin committed
53
54
  this->SetInteractor(0);
  
55
56
57
58
59
60
61
  if ( this->FileName )
    {
    delete [] this->FileName;
    }

  if ( this->InputStream )
    {
62
    this->InputStream->clear();
63
64
65
66
67
68
69
70
71
    delete this->InputStream;
    this->InputStream = NULL;
    }

  if ( this->OutputStream )
    {
    delete this->OutputStream;
    this->OutputStream = NULL;
    }
Will Schroeder's avatar
Will Schroeder committed
72
73
74
75
76
77
  
  if ( this->InputString )
    {
    delete [] this->InputString;
    this->InputString = NULL;
    }
78
79
}

80
//----------------------------------------------------------------------------
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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);

Karthik Krishnan's avatar
Karthik Krishnan committed
105
106
107
108
109
    // Make sure that the interactor does not exit in response
    // to a StartEvent. The Interactor has code to allow others to handle
    // the event look of they want to
    i->HandleEventLoop = 1;

110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
    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);
Karthik Krishnan's avatar
Karthik Krishnan committed
126
    this->Interactor->HandleEventLoop = 0;
127
128
129
130
131

    this->InvokeEvent(vtkCommand::DisableEvent,NULL);
    }
}

132
//----------------------------------------------------------------------------
133
134
135
136
137
138
139
140
141
142
143
144
145
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;
        }
146
147
148
      
      // Use C locale. We don't want the user-defined locale when we write
      // float values.
149
      (*this->OutputStream).imbue(std::locale::classic());
150
      
Will Schroeder's avatar
Will Schroeder committed
151
152
      *this->OutputStream << "# StreamVersion " 
                          << vtkInteractorEventRecorder::StreamVersion << "\n";
153
154
      }
    
Will Schroeder's avatar
Will Schroeder committed
155
    vtkDebugMacro(<<"Recording");
156
157
158
159
    this->State = vtkInteractorEventRecorder::Recording;
    }
}

160
//----------------------------------------------------------------------------
161
162
163
164
void vtkInteractorEventRecorder::Play()
{
  if ( this->State == vtkInteractorEventRecorder::Start )
    {
Will Schroeder's avatar
Will Schroeder committed
165
    if ( this->ReadFromInputString )
166
      {
Will Schroeder's avatar
Will Schroeder committed
167
      vtkDebugMacro(<< "Reading from InputString");
168
169
170
171
172
173
      size_t len = 0;
      if ( this->InputString != NULL )
        {
        len = strlen(this->InputString);
        }
      if ( len == 0 )
Will Schroeder's avatar
Will Schroeder committed
174
175
176
177
        {
        vtkErrorMacro(<< "No input string specified");
        return;
        }
178
      std::string inputStr(this->InputString, len);
Bill Lorensen's avatar
Bill Lorensen committed
179
180
181
182
      if (this->InputStream)
        {
        delete this->InputStream;
        }
183
      this->InputStream = new vtksys_ios::istringstream(inputStr);
184
185
      if (this->InputStream->fail())
        {
Will Schroeder's avatar
Will Schroeder committed
186
        vtkErrorMacro(<< "Unable to read from string");
187
188
189
190
        delete this->InputStream;
        return;
        }
      }
Will Schroeder's avatar
Will Schroeder committed
191
192
193
194
195
196
197
198
199
200
201
202
203
    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;
          }
        }
      }
204
205
206
207
208

    vtkDebugMacro(<<"Playing");
    this->State = vtkInteractorEventRecorder::Playing;

    // Read events and invoke them on the object in question
209
    char event[128], keySym[64];
210
    int pos[2], ctrlKey, shiftKey, keyCode, repeatCount;
211
    float stream_version = 0.0f, tempf;
212
    vtksys_stl::string line;
213
    
214
    while ( vtksys::SystemTools::GetLineFromStream(*this->InputStream, line) )
215
      {
216
      vtksys_ios::istringstream iss(line);
217
218
219
      
      // Use classic locale, we don't want to parse float values with
      // user-defined locale.
220
      iss.imbue(std::locale::classic());
221
      
222
223
      iss.width(256);
      iss >> event;
224
225
226
227
228
229
230

      // Quick skip comment
      if (*event == '#')
        {
        // Parse the StreamVersion (not using >> since comment could be empty)
        // Expecting: # StreamVersion x.y

231
232
        if (strlen(line.c_str()) > 16 &&
          !strncmp(line.c_str(), "# StreamVersion ", 16))
233
          {
234
          int res = sscanf(line.c_str() + 16, "%f", &tempf);
235
236
237
238
239
240
241
242
243
          if (res && res != EOF)
            {
            stream_version = tempf;
            }
          }
        }
      else
        {
        unsigned long ievent = vtkCommand::GetEventIdFromString(event);
244
        if (ievent != vtkCommand::NoEvent)
245
246
247
248
249
          {
          if (stream_version >= 1.1)
            {
            // We could grab the time info here
            }
250
251
252
253
254
255
256
257
          iss >> pos[0];
          iss >> pos[1];
          iss >> ctrlKey;
          iss >> shiftKey;
          iss >> keyCode;
          iss >> repeatCount;
          iss >> keySym;

258
259
260
          this->Interactor->SetEventPosition(pos);
          this->Interactor->SetControlKey(ctrlKey);
          this->Interactor->SetShiftKey(shiftKey);
261
          this->Interactor->SetKeyCode(static_cast<char>(keyCode));
262
263
          this->Interactor->SetRepeatCount(repeatCount);
          this->Interactor->SetKeySym(keySym);
264

265
266
267
          this->Interactor->InvokeEvent(ievent, NULL);
          }
        }
268
269
270
271
272
273
      }
    }

  this->State = vtkInteractorEventRecorder::Start;
}

274
//----------------------------------------------------------------------------
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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);
}

291
//----------------------------------------------------------------------------
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
// 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();
}

321
//----------------------------------------------------------------------------
322
323
324
325
326
327
328
329
330
331
332
333
334
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:
Ken Martin's avatar
Ken Martin committed
335
336
      // if the interactor is being deleted then remove the event handlers
      self->SetInteractor(0);
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
      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
    }
}

357
//----------------------------------------------------------------------------
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
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();
    }
}

386
//----------------------------------------------------------------------------
387
388
389
390
391
392
393
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 << " "
394
395
396
397
398
399
400
401
402
                      << keyCode << " " << repeatCount << " ";
  if ( keySym )
    {
    *this->OutputStream << keySym << "\n";
    }
  else
    {
    *this->OutputStream << "0\n";
    }
403
404
}
  
405
//----------------------------------------------------------------------------
406
407
408
409
void vtkInteractorEventRecorder::ReadEvent()
{
}

410
//----------------------------------------------------------------------------
411
412
413
414
415
416
417
418
void vtkInteractorEventRecorder::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if (this->FileName)
    {
    os << indent << "File Name: " << this->FileName << "\n";
    }
Will Schroeder's avatar
Will Schroeder committed
419
420
421
422
423
424
425
426
427
428
429
430

  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";
    }
431
432
433
434
435
436
437
}