2008/10/25/02.33.30
Adding basic undo/redo to an AIR app using AS3
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} )
Original post by richard.lyman and software by Elliott Back