Add Undo/Redo to the Scene Editor - Rollback visibility is limited to 20 steps since it's ocpying the entire model at each step.

git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@900 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Mike Thomas
2010-03-11 00:54:14 +00:00
parent c2500248db
commit b8b1a414be
2 changed files with 78 additions and 3 deletions
@@ -72,7 +72,7 @@ public class EditorFrame extends ManagedJFrame
{ {
_writer = writer; _writer = writer;
// treat a closing window as a request to quit // treat a closing window as a request to quit
addWindowListener(new WindowAdapter () { addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing (WindowEvent e) { public void windowClosing (WindowEvent e) {
handleQuit(null); handleQuit(null);
@@ -96,7 +96,7 @@ public class EditorFrame extends ManagedJFrame
System.getProperty("user.dir")); System.getProperty("user.dir"));
} }
_chooser = (target == null) ? new JFileChooser() : new JFileChooser(target); _chooser = (target == null) ? new JFileChooser() : new JFileChooser(target);
_chooser.setFileFilter(new FileFilter () { _chooser.setFileFilter(new FileFilter() {
@Override public boolean accept (File f) { @Override public boolean accept (File f) {
return (f.isDirectory() || f.getName().endsWith(".xml")); return (f.isDirectory() || f.getName().endsWith(".xml"));
} }
@@ -272,6 +272,14 @@ public class EditorFrame extends ManagedJFrame
accel = KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK); accel = KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.CTRL_MASK);
MenuUtil.addMenuItem(menuActions, "Update mini view", MenuUtil.addMenuItem(menuActions, "Update mini view",
KeyEvent.VK_M, accel, this, "updateMiniView"); KeyEvent.VK_M, accel, this, "updateMiniView");
accel = KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK);
MenuUtil.addMenuItem(menuActions, "Undo",
KeyEvent.VK_Z, accel, this, "undo");
accel = KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK);
MenuUtil.addMenuItem(menuActions, "Redo",
KeyEvent.VK_Y, accel, this, "redo");
} }
protected void setScene (StageScene scene) protected void setScene (StageScene scene)
@@ -494,6 +502,16 @@ public class EditorFrame extends ManagedJFrame
_scrollBox.updateView(); _scrollBox.updateView();
} }
public void undo (ActionEvent evt)
{
_svpanel.undo();
}
public void redo (ActionEvent evt)
{
_svpanel.redo();
}
/** /**
* Handles a request to open the preferences dialog. * Handles a request to open the preferences dialog.
*/ */
@@ -23,6 +23,7 @@ package com.threerings.stage.tools.editor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.awt.AlphaComposite; import java.awt.AlphaComposite;
@@ -220,6 +221,8 @@ public class EditorScenePanel extends StageScenePanel
*/ */
protected void placeTile (int x, int y) protected void placeTile (int x, int y)
{ {
markCheckpoint();
Rectangle drag = clearTileSelectRegion(x, y); Rectangle drag = clearTileSelectRegion(x, y);
// sanity check // sanity check
@@ -250,6 +253,8 @@ public class EditorScenePanel extends StageScenePanel
*/ */
protected void deleteTile (int x, int y) protected void deleteTile (int x, int y)
{ {
markCheckpoint();
Rectangle drag = clearTileSelectRegion(x, y); Rectangle drag = clearTileSelectRegion(x, y);
log.info("Deleting " + drag); log.info("Deleting " + drag);
@@ -301,6 +306,8 @@ public class EditorScenePanel extends StageScenePanel
*/ */
protected void editTile (int x, int y) protected void editTile (int x, int y)
{ {
markCheckpoint();
// bail if we're not hovering over a scene object // bail if we're not hovering over a scene object
if (_hobject == null || !(_hobject instanceof SceneObject)) { if (_hobject == null || !(_hobject instanceof SceneObject)) {
return; return;
@@ -332,6 +339,8 @@ public class EditorScenePanel extends StageScenePanel
*/ */
protected void editPortal (EditablePortal portal) protected void editPortal (EditablePortal portal)
{ {
markCheckpoint();
// create our portal dialog if we haven't yet // create our portal dialog if we haven't yet
if (_dialogPortal == null) { if (_dialogPortal == null) {
_dialogPortal = new PortalDialog(_ctx, this); _dialogPortal = new PortalDialog(_ctx, this);
@@ -397,6 +406,8 @@ public class EditorScenePanel extends StageScenePanel
break; break;
case EditorModel.ACTION_PLACE_PORTAL: case EditorModel.ACTION_PLACE_PORTAL:
markCheckpoint();
Point fcoords = getFullCoords(mx, my); Point fcoords = getFullCoords(mx, my);
// mouse button three is delete // mouse button three is delete
if (event.getButton() == MouseEvent.BUTTON3) { if (event.getButton() == MouseEvent.BUTTON3) {
@@ -939,7 +950,7 @@ public class EditorScenePanel extends StageScenePanel
/** /**
* Paint the specified StageLocation * Paint the specified StageLocation
*/ */
protected void paintLocation(Graphics2D gfx, StageLocation loc, Color color, boolean highlight) protected void paintLocation (Graphics2D gfx, StageLocation loc, Color color, boolean highlight)
{ {
// get the portal's center coordinate // get the portal's center coordinate
Point spos = new Point(); Point spos = new Point();
@@ -1118,6 +1129,49 @@ public class EditorScenePanel extends StageScenePanel
} }
} }
protected void markCheckpoint ()
{
_undo.preserve();
_redo.clear();
}
public void undo ()
{
if (_undo.size() > 0) {
_redo.preserve();
_undo.rollback();
}
}
public void redo ()
{
if (_redo.size() > 0) {
_undo.preserve();
_redo.rollback();
}
}
protected class UndoStack extends LinkedList<MisoSceneModel>
{
public void preserve () {
addFirst(_model.clone());
if (size() > MAX_UNDO_SIZE) {
removeLast();
}
}
public void rollback () {
if (size() > 0) {
_model = removeFirst();
_blocks.clear();
refreshScene();
}
}
}
protected static final int MAX_UNDO_SIZE = 20;
/** Provides access to stuff. */ /** Provides access to stuff. */
protected EditorContext _ctx; protected EditorContext _ctx;
@@ -1177,6 +1231,9 @@ public class EditorScenePanel extends StageScenePanel
/** The object currently being edited by the object editor dialog. */ /** The object currently being edited by the object editor dialog. */
protected SceneObject _eobject; protected SceneObject _eobject;
protected UndoStack _undo = new UndoStack();
protected UndoStack _redo = new UndoStack();
/** The triangle used to render a portal on-screen. */ /** The triangle used to render a portal on-screen. */
protected static Polygon _locTri; protected static Polygon _locTri;