[vtk-developers] undo / redo for widgets

Karthik Krishnan karthik.krishnan at kitware.com
Thu Nov 26 00:34:52 EST 2009


As far as the paintbrush widgets (in VTKEdge) go, they do support
Undo/Redo with a HistoryStack of size "N". Where N can range from 0
(no undo/redo) to infinite (if you had infinite memory). The states
are essentially pushed into the stack and one can traverse down or up
the stack to undo and redo, much like Dean proposed.


Three thoughts and one alternative solution :

1. I wonder about the implications on widgets that manipulate data in
an irreversible fashion... But I guess given that the Undo/Redo can be
disabled, its ok.


2. Then there is the question of what's popped into the HistoryQueue.
For instance on the contourWidget, I guess we would take a snapshot of
all the control points. Do we take a snapshot of the contour node
properties as well, so if one were to change the contour color, that's
undone ?


3. Then there is question of how often we take snapshots of the
widget. Is this done at each invocation of EndInteractionEvent ? Or
every couple 5th EndInteractionEvent ? Or do we let the user do this
explicitly ?


4. At some point, I had the idea of adding XML IO to all the widgets.
This is how we VolView creates session files. So every widget and
representation used in VolView has a corresponding XML reader/writer
for instance :

  vtkXMLAngleWidgetReader,
  vtkXMLAngleWidgetWriter,
  vtkXMLAngleRepresentation2DReader,
  vtkXMLAngleRepresentation2DWriter.

At any point the application can ask the widget to serialize itself
and restore it exactly to that state when needed. This framework could
be useful for maintaining state in a stream, or serializing to a file.

An class can maintain a queue of these stringstreams for any widget.
Something like...

  class vtkAbstractWidgetStates< class TAbstractWidget >
    {
    void SetWidget( TAbstractWidget * );

    vtkTimeStamp Serialize( std::ostringstream &os );
    bool UnSerialize( std::ostringstream &os );

    void Undo() { --pos; UnSerialize( pos->second ); }
    void Redo()..

    void RecordState() { // Create new stringstream. Serialize, pushback }

    std::map< vtkTimeStamp, std::ostringstream * > History;
    HistoryIterator pos;
    }

This takes care of Issue (2), since serialization means that the
widget should be entirely reproducible from the state...
Also, all the undo / redo code is kept out of the widget /
repesentation and done by the stateManager.


That said, I haven't the forethought to see several potential
pitfalls, so this may just be a bogus suggestion.


Thanks



On Wed, Nov 25, 2009 at 5:24 PM, Dean Inglis <dean.inglis at camris.ca> wrote:
> Hi Andrew,
>
> I was thinking unlimited, at least as far as memory would allow,
> but it could be capped and probably should be at some
> reasonable level depending on the widget representation complexity.
> maybe the API could be
>
>> int CanUndo(){return 0;} // by default for all classes that decide not
>> int CanRedo(){return 0;} // to reimplement these methods return false
>> void UpdateHistory(){}    // or some other name  and by default do nothing
>  void SetMaximumHistorySize()
>> void Undo(){}
>> void Redo(){}
>
> Dean
>
>>I must have missed the start of this thread.
>>What levels of undo/redo do you envisage having? Or will it be limited
>>to a single undo/redo?
>
>>Regards
>>   Andrew
>
>
> On Thu, Nov 26, 2009 at 6:54 AM, Dean Inglis <dean.inglis at camris.ca> wrote:
>> Will,
>>
>> absolutely, just ran out of steam momentarily... ;)
>>
>> My impression is that vtkWidgetRepresentation could have
>> the optional methods:
>>
>> int CanUndo(){return 0;} // by default for all classes that decide not
>> int CanRedo(){return 0;} // to reimplement these methods return false
>> void TakeSnapShot(){}    // or some other name  and by default do nothing
>> void Undo(){}
>> void Redo(){}
>>
>> Implementation would then be representation dependent.
>>
>> Dean
>>
>> -----Original Message-----
>> From: Will Schroeder [mailto:will.schroeder at kitware.com]
>> Sent: November-25-09 2:37 PM
>> To: dean.inglis at camris.ca
>> Cc: VTK Developers
>> Subject: Re: undo / redo for widgets
>>
>> Dean-
>>
>> Well I can imagine any widget benefiting, for example slider widget,
>> you may want to undo a value change; affine or box widget; reset a
>> transformation, etc.
>>
>> Am I answering your question? Doe this make sense?
>>
>> Will
>>
>> On Wed, Nov 25, 2009 at 2:32 PM, Dean Inglis <dean.inglis at camris.ca>
> wrote:
>>> Hi Will,
>>>
>>> I'm breaking this off into a separate thread.  What other (VTK) widgets
>>> and/or instances would it be desirable to have undo redo?
>>>
>>> Dean
>>>
>>>
>>>>I'm rethinking my answer on this one, I retract my previous statement
>>>>:-) I know there is some support for this in the paintbrush widgets; I
>>>>guess my premature reaction is more of a question: can we step back
>>>>and think about redo/undo at a higher level across all widgets?
>>>
>>>>Will
>>>
>>> On Wed, Nov 25, 2009 at 1:46 PM, Will Schroeder
>>> <will.schroeder at kitware.com> wrote:
>>>> IMHO Undo/redo is an application level feature. I do not think it
>>>> belongs in individual classes.
>>>>
>>>> If you want to raise a discussion about general approaches for
>>>> undo/redo that is a different matter.
>>>>
>>>> Will
>>>>
>>>> On Wed, Nov 25, 2009 at 1:33 PM, Dean Inglis <dean.inglis at sympatico.ca>
>>> wrote:
>>>>> Hi all,
>>>>>
>>>>> I would like to add undo redo capability for vtkContourWidget.  The
>>>>> implementation would be to have vtkContourRepresentation's internals
>>>>> modified as follows:
>>>>> 1) add Copy methods to the vtkContourRepresentationNode:
>>>>>
>>>>>  void Copy( vtkContourRepresentationNode* node )
>>>>>  {
>>>>>    vtkstd::vector< vtkContourRepresentationPoint* > points =
>>> node->Points;
>>>>>    vtkstd::vector< vtkContourRepresentationPoint* >::iterator it1, it2;
>>>>>
>>>>>    memcpy( this->WorldPosition, node->WorldPosition, 3 * sizeof( double
>> )
>>>>> );
>>>>>    memcpy( this->WorldOrientation, node->WorldOrientation, 9 * sizeof(
>>>>> double ) );
>>>>>    memcpy( this->NormalizedDisplayPosition,
>>>>> node->NormalizedDisplayPosition, 2 * sizeof( double ) );
>>>>>    this->Selected = node->Seleced;
>>>>>
>>>>>    this->Points.resize( points.size() );
>>>>>    for( it1 = points.begin(), it2 = this->Points.begin();
>>>>>         it1 != points.end() && it2 != this->Points.end();
>>>>>         it1++, it2++ )
>>>>>    {
>>>>>      ( *it2 ) = new vtkContourRepresentationPoint;
>>>>>      memcpy( ( *it2 )->WorldPosition, ( *it1 )->WorldPosition,
>>>>>        3 * sizeof( double ) );
>>>>>      memcpy( ( *it2 )->NormalizedDisplayPosition, ( *it1
>>>>> )->NormalizedDisplayPosition,
>>>>>        2 * sizeof( double ) );
>>>>>    }
>>>>>  }
>>>>>
>>>>> and the vtkContourRepresentationInternals:
>>>>>
>>>>>  void Copy( vtkContourRepresentationInternals* internal )
>>>>>  {
>>>>>    vtkstd::vector< vtkContourRepresentationNode* > nodes =
>>> internal->Nodes;
>>>>>    vtkstd::vector< vtkContourRepresentationNode* >::iterator it1, it2;
>>>>>
>>>>>    this->Nodes.resize( nodes.size() );
>>>>>    for( it1 = nodes.begin(), it2 = this->Nodes.begin();
>>>>>         it1 != nodes.end() && it2 != this->Nodes.end();
>>>>>         it1++, it2++ )
>>>>>    {
>>>>>      ( *it2 ) = new vtkContourRepresentationNode;
>>>>>      ( *it2 )->Copy( *it1 );
>>>>>    }
>>>>>  }
>>>>>
>>>>> and implement the following:
>>>>>
>>>>>  // Description:
>>>>>  // Records the current layout of nodes adding them to the node history
>>>>> list
>>>>>  // so that they can be undone/redone.
>>>>>  virtual void TakeSnapshot();
>>>>>
>>>>>  // Description:
>>>>>  // A history of changes to the layout of nodes is kept internally and
>>>>>  // externally by calling TakeSnapshot().
>>>>>  // These two methods are used to go back to earlier changes to the
>>> contour
>>>>>  // or return to more recent ones.
>>>>>  virtual void Undo();
>>>>>  virtual void Redo();
>>>>>
>>>>>  // Description:
>>>>>  // Methods to determine whether there is any history left to undo or
>>> redo.
>>>>>  virtual int CanUndo();
>>>>>  virtual int CanRedo();
>>>>>
>>>>> by maintaining protected members:
>>>>>
>>>>> //BTX
>>>>>  vtkstd::vector< vtkContourRepresentationInternals* >
>>>>> InternalHistory;
>>>>>  vtkstd::vector< vtkContourRepresentationInternals* >::iterator
>>>>> InternalHistoryIterator;
>>>>> //ETX
>>>>>
>>>>> Also, can the SelectedNodesCursorShape be exposed through the public
> API
>>>>> of vtkOrientedGlyphContourRepresentation as is done for SetCursorShape
>>> and
>>>>> SetActiveCursorShape ?
>>>>>
>>>>> Dean
>>>>>
>>>>> _______________________________________________
>>>>> Powered by www.kitware.com
>>>>>
>>>>> Visit other Kitware open-source projects at
>>> http://www.kitware.com/opensource/opensource.html
>>>>>
>>>>> Follow this link to subscribe/unsubscribe:
>>>>> http://www.vtk.org/mailman/listinfo/vtk-developers
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> William J. Schroeder, PhD
>>>> Kitware, Inc.
>>>> 28 Corporate Drive
>>>> Clifton Park, NY 12065
>>>> will.schroeder at kitware.com
>>>> http://www.kitware.com
>>>> (518) 881-4902
>>>>
>>>
>>>
>>>
>>> --
>>> William J. Schroeder, PhD
>>> Kitware, Inc.
>>> 28 Corporate Drive
>>> Clifton Park, NY 12065
>>> will.schroeder at kitware.com
>>> http://www.kitware.com
>>> (518) 881-4902
>>> _______________________________________________
>>> Powered by www.kitware.com
>>>
>>> Visit other Kitware open-source projects at
>>> http://www.kitware.com/opensource/opensource.html
>>>
>>> Follow this link to subscribe/unsubscribe:
>>> http://www.vtk.org/mailman/listinfo/vtk-developers
>>>
>>>
>>
>>
>>
>> --
>> William J. Schroeder, PhD
>> Kitware, Inc.
>> 28 Corporate Drive
>> Clifton Park, NY 12065
>> will.schroeder at kitware.com
>> http://www.kitware.com
>> (518) 881-4902
>>
>> _______________________________________________
>> Powered by www.kitware.com
>>
>> Visit other Kitware open-source projects at
> http://www.kitware.com/opensource/opensource.html
>>
>> Follow this link to subscribe/unsubscribe:
>> http://www.vtk.org/mailman/listinfo/vtk-developers
>>
>>
>
>
>
> --
> ___________________________________________
> Andrew J. P. Maclean
> Centre for Autonomous Systems
> The Rose Street Building J04
> The University of Sydney  2006  NSW
> AUSTRALIA
> Ph: +61 2 9351 3283
> Fax: +61 2 9351 7474
> URL: http://www.acfr.usyd.edu.au/
> ___________________________________________
>
> _______________________________________________
> Powered by www.kitware.com
>
> Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html
>
> Follow this link to subscribe/unsubscribe:
> http://www.vtk.org/mailman/listinfo/vtk-developers
>

_________________________________
Karthik Krishnan
R&D Engineer,
Kitware Inc.
Ph: +1 5188814919, +91 9538477060



More information about the vtk-developers mailing list