Page Index Toggle Pages: 1 Send TopicPrint
Normal Topic Undo/redo for moving a custom node with the mouse (Read 4778 times)
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Undo/redo for moving a custom node with the mouse
May 12th, 2013 at 10:22pm
Print Post  
I'm trying to implement undo/redo processing in my program now, and finding it a bit, um, challenging. I'm having several different problems, but let's start with just one of them ...

I have some custom nodes, and some custom behaviors. The custom nodes typically allow moving around with the mouse, and also resizing with the mouse. This results in calls to StartModify(), UpdateModify() and CompleteModify() methods in the node code, and these methods update the node's Bounds during the move or resize. This is all working fine, except that it isn't undo/redo compatible.

When I enable undo processing and look at the CommandHistory after moving a node with the mouse there are typically 30 or more Modify commands for a single move. Not so good.

So then I tried to implement the CompositeCmd facility. But I'm unsure where I should start the CompositeCmd running - in the StartModify() method? Similarly, I'm unsure of where I should Execute the CompositeCmd - in the CompleteModify() method?

Anyway, I have not gotten it to work properly. There is still one Modify command on CommandHistory for each mouse move, in addition to my composite command, and this messes up the undo/redo processing for mouse moves.

Are there any sample programs that show how to implement undo/redo for this kind of situation? A custom node that updates the node's Bounds during a mouse move, and I'd like to make it possible to undo (and redo) each complete mouse move with a single undo or redo operation?

Thanks.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Undo/redo for moving a custom node with the mouse
Reply #1 - May 13th, 2013 at 9:46am
Print Post  
Call the base.StartModify method to create an undo record for the operation. The Bounds property setter creates its own undo records, so in UpdateModify do not set Bounds, but call the SetBounds method instead (the method does not save undo information).

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Re: Undo/redo for moving a custom node with the mouse
Reply #2 - May 14th, 2013 at 12:02am
Print Post  
Thanks, using SetBounds() instead of setting Bounds directly certainly helped in reducing the number of commands on the CommandHistory.

But I still have the problem that something is adding a single Modify command to CommandHistory at the end of a mouse move. I'm doing _compositeCmd.Execute(); as the very last thing in the CompleteModify() method, but then when I look at CommandHistory a moment later there's a single Modify command following my composite command.

I think what this unexpected Modify command is doing is moving the node's bounds from where they were at the start of the mouse move to the final location - but I've already included that information in my composite command, at least I think so. Anyway, it's a problem that the mouse move ends up being two commands on CommandHistory instead of one.

As I asked above, is there any sample program that demonstrates doing undo for a custom node such that a mouse move of the node ends up being a single undo item?
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Undo/redo for moving a custom node with the mouse
Reply #3 - May 14th, 2013 at 4:24pm
Print Post  
Do you really need the composite command now that you know how to get a single ModifyCmd instance? If all you need to save for undo is the position of nodes, the modify command created by the base class should be enough.

If you need to store additional modification info for later undo, I think the expected way is to override the CreateState, SaveState and RestoreState methods in your custom class, and respectively return a DiagramNodeState-derived object, and save / restore its additional fields.

An easier solution might be to just call the CommandHistory.MergeUndoRecords method to merge your additional commands with the modification one.

I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Re: Undo/redo for moving a custom node with the mouse
Reply #4 - May 16th, 2013 at 11:44pm
Print Post  
Stoyo wrote on May 14th, 2013 at 4:24pm:
If you need to store additional modification info for later undo, I think the expected way is to override the CreateState, SaveState and RestoreState methods in your custom class, and respectively return a DiagramNodeState-derived object, and save / restore its additional fields.

I think this is what I need to do. But I can't find any sample program that does this. Are there any? I'm thinking it will be much easier for me to figure out how to do this if there was a sample program that demonstrated it.

Thanks.
  
Back to top
 
IP Logged
 
Stoyo
God Member
*****
Offline


MindFusion support

Posts: 13230
Joined: Jul 20th, 2005
Re: Undo/redo for moving a custom node with the mouse
Reply #5 - May 17th, 2013 at 12:45pm
Print Post  
Here's an example:

Code
Select All
class MyNode : DiagramNode
{
	protected override DiagramItemState CreateState()
	{
		return new MyState();
	}

	protected override void SaveState(DiagramItemState state)
	{
		base.SaveState(state);

		var myState = (MyState)state;
		myState.counter = counter;
	}

	protected override void RestoreState(DiagramItemState state)
	{
		base.RestoreState(state);

		var myState = (MyState)state;
		counter = myState.counter;
	}

	protected override void UpdateModify(PointF current, InteractionState ist)
	{
		base.UpdateModify(current, ist);
		counter++;
	}

	public override void DrawLocal(MindFusion.Drawing.IGraphics graphics, RenderOptions options)
	{
		graphics.DrawRectangle(Pens.Black, GetLocalBounds());
	}

	int counter;
}

class MyState : DiagramNodeState
{
	internal int counter;
} 



I hope that helps,
Stoyan
  
Back to top
 
IP Logged
 
Rennie
Full Member
***
Offline


I Love MindFusion!

Posts: 108
Location: Copenhagen, Denmark
Joined: Jul 17th, 2012
Re: Undo/redo for moving a custom node with the mouse
Reply #6 - May 21st, 2013 at 3:11am
Print Post  
> I hope that helps

Yes, that was the key! I've got it working using this technique, and it's much simplier and more "correct" than my previous attempts with a combination of a composite command plus a Command-derived item. Plus it works.

Thanks for your great support.
  
Back to top
 
IP Logged
 
Page Index Toggle Pages: 1
Send TopicPrint