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;
// treat a closing window as a request to quit
addWindowListener(new WindowAdapter () {
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing (WindowEvent e) {
handleQuit(null);
@@ -96,7 +96,7 @@ public class EditorFrame extends ManagedJFrame
System.getProperty("user.dir"));
}
_chooser = (target == null) ? new JFileChooser() : new JFileChooser(target);
_chooser.setFileFilter(new FileFilter () {
_chooser.setFileFilter(new FileFilter() {
@Override public boolean accept (File f) {
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);
MenuUtil.addMenuItem(menuActions, "Update mini view",
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)
@@ -494,6 +502,16 @@ public class EditorFrame extends ManagedJFrame
_scrollBox.updateView();
}
public void undo (ActionEvent evt)
{
_svpanel.undo();
}
public void redo (ActionEvent evt)
{
_svpanel.redo();
}
/**
* 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.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.awt.AlphaComposite;
@@ -220,6 +221,8 @@ public class EditorScenePanel extends StageScenePanel
*/
protected void placeTile (int x, int y)
{
markCheckpoint();
Rectangle drag = clearTileSelectRegion(x, y);
// sanity check
@@ -250,6 +253,8 @@ public class EditorScenePanel extends StageScenePanel
*/
protected void deleteTile (int x, int y)
{
markCheckpoint();
Rectangle drag = clearTileSelectRegion(x, y);
log.info("Deleting " + drag);
@@ -301,6 +306,8 @@ public class EditorScenePanel extends StageScenePanel
*/
protected void editTile (int x, int y)
{
markCheckpoint();
// bail if we're not hovering over a scene object
if (_hobject == null || !(_hobject instanceof SceneObject)) {
return;
@@ -332,6 +339,8 @@ public class EditorScenePanel extends StageScenePanel
*/
protected void editPortal (EditablePortal portal)
{
markCheckpoint();
// create our portal dialog if we haven't yet
if (_dialogPortal == null) {
_dialogPortal = new PortalDialog(_ctx, this);
@@ -397,6 +406,8 @@ public class EditorScenePanel extends StageScenePanel
break;
case EditorModel.ACTION_PLACE_PORTAL:
markCheckpoint();
Point fcoords = getFullCoords(mx, my);
// mouse button three is delete
if (event.getButton() == MouseEvent.BUTTON3) {
@@ -939,7 +950,7 @@ public class EditorScenePanel extends StageScenePanel
/**
* 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
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. */
protected EditorContext _ctx;
@@ -1177,6 +1231,9 @@ public class EditorScenePanel extends StageScenePanel
/** The object currently being edited by the object editor dialog. */
protected SceneObject _eobject;
protected UndoStack _undo = new UndoStack();
protected UndoStack _redo = new UndoStack();
/** The triangle used to render a portal on-screen. */
protected static Polygon _locTri;