vtkInteractorEventRecorder.cxx 12.3 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
  this->SetInteractor(0);
54

55
  delete [] this->FileName;
56
57
58

  if ( this->InputStream )
    {
59
    this->InputStream->clear();
60
61
62
63
    delete this->InputStream;
    this->InputStream = NULL;
    }

64
65
  delete this->OutputStream;
  this->OutputStream = NULL;
66

67
68
  delete [] this->InputString;
  this->InputString = NULL;
69
70
}

71
//----------------------------------------------------------------------------
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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;
      }
88

89
90
91
92
    this->Enabled = 1;

    // listen to any event
    vtkRenderWindowInteractor *i = this->Interactor;
93
    i->AddObserver(vtkCommand::AnyEvent, this->EventCallbackCommand,
94
95
                   this->Priority);

Karthik Krishnan's avatar
Karthik Krishnan committed
96
97
98
99
100
    // 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;

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
    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
117
    this->Interactor->HandleEventLoop = 0;
118
119
120
121
122

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

123
//----------------------------------------------------------------------------
124
125
126
127
128
129
130
131
132
133
134
135
136
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;
        }
137

138
139
      // Use C locale. We don't want the user-defined locale when we write
      // float values.
140
      (*this->OutputStream).imbue(std::locale::classic());
141
142

      *this->OutputStream << "# StreamVersion "
Will Schroeder's avatar
Will Schroeder committed
143
                          << vtkInteractorEventRecorder::StreamVersion << "\n";
144
      }
145

Will Schroeder's avatar
Will Schroeder committed
146
    vtkDebugMacro(<<"Recording");
147
148
149
150
    this->State = vtkInteractorEventRecorder::Recording;
    }
}

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

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

    // Read events and invoke them on the object in question
200
    char event[128], keySym[64];
201
    int pos[2], ctrlKey, shiftKey, keyCode, repeatCount;
202
    float stream_version = 0.0f, tempf;
203
    vtksys_stl::string line;
204

205
    while ( vtksys::SystemTools::GetLineFromStream(*this->InputStream, line) )
206
      {
207
      vtksys_ios::istringstream iss(line);
208

209
210
      // Use classic locale, we don't want to parse float values with
      // user-defined locale.
211
      iss.imbue(std::locale::classic());
212

213
214
      iss.width(256);
      iss >> event;
215
216
217
218
219
220
221

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

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

249
250
251
          this->Interactor->SetEventPosition(pos);
          this->Interactor->SetControlKey(ctrlKey);
          this->Interactor->SetShiftKey(shiftKey);
252
          this->Interactor->SetKeyCode(static_cast<char>(keyCode));
253
254
          this->Interactor->SetRepeatCount(repeatCount);
          this->Interactor->SetKeySym(keySym);
255

256
257
258
          this->Interactor->InvokeEvent(ievent, NULL);
          }
        }
259
260
261
262
263
264
      }
    }

  this->State = vtkInteractorEventRecorder::Start;
}

265
//----------------------------------------------------------------------------
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
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);
}

282
//----------------------------------------------------------------------------
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// 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)
    {
303
    i->AddObserver(vtkCommand::CharEvent,
304
                   this->KeyPressCallbackCommand, this->Priority);
305
    i->AddObserver(vtkCommand::DeleteEvent,
306
307
                   this->KeyPressCallbackCommand, this->Priority);
    }
308

309
310
311
  this->Modified();
}

312
//----------------------------------------------------------------------------
313
void vtkInteractorEventRecorder::ProcessCharEvent(vtkObject* object,
314
                                                  unsigned long event,
315
                                                  void* clientData,
316
317
                                                  void* vtkNotUsed(callData))
{
318
  vtkInteractorEventRecorder* self =
319
    reinterpret_cast<vtkInteractorEventRecorder *>( clientData );
320
  vtkRenderWindowInteractor* rwi =
321
322
323
324
325
    static_cast<vtkRenderWindowInteractor *>( object );

  switch(event)
    {
    case vtkCommand::DeleteEvent:
Ken Martin's avatar
Ken Martin committed
326
327
      // if the interactor is being deleted then remove the event handlers
      self->SetInteractor(0);
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
      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
    }
}

348
//----------------------------------------------------------------------------
349
void vtkInteractorEventRecorder::ProcessEvents(vtkObject* object,
350
                                               unsigned long event,
351
                                               void* clientData,
352
353
                                               void* vtkNotUsed(callData))
{
354
  vtkInteractorEventRecorder* self =
355
    reinterpret_cast<vtkInteractorEventRecorder *>( clientData );
356
  vtkRenderWindowInteractor* rwi =
357
358
359
360
361
362
363
364
365
366
367
368
    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),
369
                         rwi->GetEventPosition(), rwi->GetControlKey(),
370
371
372
373
374
375
376
                         rwi->GetShiftKey(), rwi->GetKeyCode(),
                         rwi->GetRepeatCount(), rwi->GetKeySym());
      }
    self->OutputStream->flush();
    }
}

377
//----------------------------------------------------------------------------
378
379
void vtkInteractorEventRecorder::WriteEvent(const char* event, int pos[2],
                                            int ctrlKey, int shiftKey,
380
381
382
383
384
                                            int keyCode, int repeatCount,
                                            char* keySym)
{
  *this->OutputStream << event << " " << pos[0] << " " << pos[1] << " "
                      << ctrlKey << " " << shiftKey << " "
385
386
387
388
389
390
391
392
393
                      << keyCode << " " << repeatCount << " ";
  if ( keySym )
    {
    *this->OutputStream << keySym << "\n";
    }
  else
    {
    *this->OutputStream << "0\n";
    }
394
}
395

396
//----------------------------------------------------------------------------
397
398
399
400
void vtkInteractorEventRecorder::ReadEvent()
{
}

401
//----------------------------------------------------------------------------
402
403
404
405
406
407
408
409
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
410

411
  os << indent << "ReadFromInputString: "
Will Schroeder's avatar
Will Schroeder committed
412
413
414
415
416
417
418
419
420
421
     << (this->ReadFromInputString ? "On\n" : "Off\n");

  if ( this->InputString )
    {
    os << indent << "Input String: " << this->InputString << "\n";
    }
  else
    {
    os << indent << "Input String: (None)\n";
    }
422
423
424
}


425

426
427
428