homeresumeabout
Adding basic undo/redo to an AIR app using AS3
08.10.25
I was hoping that it wouldn't take too much code (and that it'd look cool since it is ActionScript), and I was pleasantly surprised:
private var _undo : Array;
private var _redo : Array;
private function verifyUndoRedo() : void {
	mainMenuData..menuitem.(attribute('data')=='undo').@enabled = _undo.length > 0;
	mainMenuData..menuitem.(attribute('data')=='redo').@enabled = _redo.length > 0;
}
public function addBasicUndoItem( s : Object, o : *, n : * ) : void {
	_redo = [];
	_undo.push( {
		undo:function():Object{ for( var p : * in o ){ s[p] = o[p]; }; return this; },
		redo:function():Object{ for( var p : * in n ){ s[p] = n[p]; }; return this; }
	} );
	verifyUndoRedo();
}
private function undo() : void { if( _undo.length > 0 ){ _redo.push( _undo.pop().undo() ); } verifyUndoRedo(); }
private function redo() : void { if( _redo.length > 0 ){ _undo.push( _redo.pop().redo() ); } verifyUndoRedo(); }

'Course you'll want to make sure your _undo and _redo Arrays are initialized to [] and that you're listening to the Ctrl-Z and Ctrl-Y KeyboardEvents...
public function onInvoke( invokeEvent : InvokeEvent ) : void {
	stage.addEventListener( KeyboardEvent.KEY_DOWN, handleKeyDown );
}

private function handleKeyDown( e : KeyboardEvent ) : void {
	if( e.charCode == 122 && e.keyCode == 90 && e.ctrlKey ){
		undo();
	}else if( e.charCode == 121 && e.keyCode == 89 && e.ctrlKey ){
		redo();
	}
}

... and you'll probably want to setup an easy to manage Menu...
<mx:XML format="e4x" id="mainMenuData" xmlns="" >
	<root>
		<menuitem label="File">
			<menuitem label="Exit" data="exit" />
		</menuitem>
		<menuitem label="Edit">
			<menuitem label="Undo" data="undo" enabled="false" />
			<menuitem label="Redo" data="redo" enabled="false" />
		</menuitem>
	</root>
</mx:XML>
<mx:MenuBar width="100%" dataProvider="{mainMenuData}" labelField="@label" itemClick="handleMenuSelection(event)" showRoot="false" />

... with it's related handleMenuSelection method...
private function handleMenuSelection( e : MenuEvent ) : void {
	if( e.item.@data == "exit" ){
		NativeApplication.nativeApplication.exit();
	}else if( e.item.@data == "undo" ){
		undo();
	}else if( e.item.@data == "redo" ){
		redo();
	}
}

... like I said, not too bad.
Using it isn't too taxing either. Assuming that you wanted to undo/redo the x and y position of an item after it had been dragged to a new position...
// Some code before the drag that set's the prevx and prevy var's to the previous x and y...
addBasicUndoItem( this, {x:prevx,y:prevy}, {x:x,y:y} )