[ease] Added undo functionality for moving and resizing elements.



commit fb7196f547d9f9326fef53af2cf47c66cefb394d
Author: Nate Stedman <natesm gmail com>
Date:   Wed May 19 03:46:45 2010 -0400

    Added undo functionality for moving and resizing elements.

 src/libease/EditorEmbed.vala    |   32 +++++++++++++++++-
 src/libease/EditorWindow.vala   |   36 +++++++++++++++++++-
 src/libease/MainToolbar.vala    |    7 ++++
 src/libease/UndoActions.vala    |   70 +++++++++++++++++++++++++++++++++++++++
 src/libease/UndoController.vala |   57 +++++++++++++++++++++++++++++++
 5 files changed, 199 insertions(+), 3 deletions(-)
---
diff --git a/src/libease/EditorEmbed.vala b/src/libease/EditorEmbed.vala
index 406d5b5..0d776e4 100644
--- a/src/libease/EditorEmbed.vala
+++ b/src/libease/EditorEmbed.vala
@@ -29,6 +29,9 @@
  */
 public class Ease.EditorEmbed : ScrollableEmbed
 {
+	// the editorwindow
+	private EditorWindow win;
+
 	// overall display
 	private Clutter.Rectangle view_background;
 	
@@ -50,6 +53,12 @@ public class Ease.EditorEmbed : ScrollableEmbed
 	private float mouse_x;
 	private float mouse_y;
 	
+	// the origin position of a dragged element
+	private float orig_x;
+	private float orig_y;
+	private float orig_w;
+	private float orig_h;
+	
 	private Document document;
 	public float zoom;
 	public bool zoom_fit;
@@ -64,10 +73,12 @@ public class Ease.EditorEmbed : ScrollableEmbed
 	 * menu item. 
 	 *
 	 * @param d The { link Document} this EditorEmbed represents.
+	 * @param w The { link EditorWindow} this EditorEmbed is part of.
 	 */
-	public EditorEmbed(Document d)
+	public EditorEmbed(Document d, EditorWindow w)
 	{
 		base(true);
+		win = w;
 
 		// set up the background
 		view_background = new Clutter.Rectangle();
@@ -323,6 +334,9 @@ public class Ease.EditorEmbed : ScrollableEmbed
 		{
 			is_dragging = false;
 			Clutter.ungrab_pointer();
+			win.add_undo_action(new MoveUndoAction(selected,
+			                                       orig_x, orig_y,
+			                                       orig_w, orig_h));
 		}
 		return true;
 	}
@@ -348,6 +362,12 @@ public class Ease.EditorEmbed : ScrollableEmbed
 				is_drag_ready = true;
 				mouse_x = event.motion.x;
 				mouse_y = event.motion.y;
+				
+				orig_x = selected.x;
+				orig_y = selected.y;
+				orig_w = selected.width;
+				orig_h = selected.height;
+				
 				return true;
 			}
 			
@@ -399,6 +419,10 @@ public class Ease.EditorEmbed : ScrollableEmbed
 		{
 			is_dragging = false;
 			sender.motion_event.disconnect(handle_motion);
+			
+			win.add_undo_action(new MoveUndoAction(selected,
+			                                       orig_x, orig_y,
+			                                       orig_w, orig_h));
 		}
 		
 		Clutter.ungrab_pointer();
@@ -425,6 +449,12 @@ public class Ease.EditorEmbed : ScrollableEmbed
 			is_drag_ready = true;
 			mouse_x = event.motion.x;
 			mouse_y = event.motion.y;
+			
+			orig_x = selected.x;
+			orig_y = selected.y;
+			orig_w = selected.width;
+			orig_h = selected.height;
+			
 			return true;
 		}
 		
diff --git a/src/libease/EditorWindow.vala b/src/libease/EditorWindow.vala
index e215ff7..8ee254b 100644
--- a/src/libease/EditorWindow.vala
+++ b/src/libease/EditorWindow.vala
@@ -43,12 +43,16 @@ public class Ease.EditorWindow : Gtk.Window
 	public Document document;
 	public Slide slide;
 	
+	// the UndoController for this window
+	private UndoController undo;
+	
 	// interface variables
 	public bool inspector_shown { get; set; }
 	public bool slides_shown { get; set; }
 	
 	// constants
-	private const int[] ZOOM_LEVELS = {10, 25, 33, 50, 66, 75, 100, 125, 150, 200, 250, 300, 400};
+	private const int[] ZOOM_LEVELS = {10, 25, 33, 50, 66, 75, 100, 125, 150,
+	                                   200, 250, 300, 400};
 	private const int ZOOM_COUNT = 13;
 
 	/**
@@ -70,6 +74,9 @@ public class Ease.EditorWindow : Gtk.Window
 		// slide display
 		var slides_win = new SlideButtonPanel(document, this);
 		
+		// undo controller
+		undo = new UndoController();
+		
 		// the inspector
 		inspector = new Gtk.HBox(false, 0);
 		var notebook = new Gtk.Notebook();
@@ -85,7 +92,7 @@ public class Ease.EditorWindow : Gtk.Window
 		inspector.pack_start(notebook, false, false, 0);
 		
 		// main editor
-		embed = new EditorEmbed(document);
+		embed = new EditorEmbed(document, this);
 		
 		// assemble middle contents			
 		var hbox = new Gtk.HBox(false, 0);
@@ -158,6 +165,13 @@ public class Ease.EditorWindow : Gtk.Window
 			player = new Player(document);
 		});
 		
+		// undo and redo
+		main_toolbar.undo.clicked.connect(() => {
+			undo.undo();
+			update_undo();
+			embed.reposition_group();
+		});
+		
 		// TODO: export HTML in a proper place
 		main_toolbar.fonts.clicked.connect(() => {
 			document.export_to_html(this);
@@ -239,6 +253,7 @@ public class Ease.EditorWindow : Gtk.Window
 		hide.connect(() => Main.remove_window(this));
 		
 		load_slide(0);
+		update_undo();
 	}
 	
 	/**
@@ -260,6 +275,23 @@ public class Ease.EditorWindow : Gtk.Window
 		embed.set_slide(slide);
 	}
 	
+	/**
+	 * Add the most recent action to the { link UndoController}.
+	 *
+	 * @param action The new { link UndoAction}.
+	 */
+	public void add_undo_action(UndoAction action)
+	{
+		undo.add_action(action);
+		update_undo();
+	}
+	
+	private void update_undo()
+	{
+		main_toolbar.undo.sensitive = undo.can_undo();
+		main_toolbar.redo.sensitive = false;
+	}
+	
 	// signal handlers
 	private void show_open_dialog()
 	{
diff --git a/src/libease/MainToolbar.vala b/src/libease/MainToolbar.vala
index 2133d83..5718650 100644
--- a/src/libease/MainToolbar.vala
+++ b/src/libease/MainToolbar.vala
@@ -30,6 +30,8 @@ public class Ease.MainToolbar : Gtk.Toolbar
 	public Gtk.ToolButton save;
 	public Gtk.ToolButton new_presentation;
 	public Gtk.ToolButton open;
+	public Gtk.ToolButton undo;
+	public Gtk.ToolButton redo;
 	public Gtk.ToolButton inspector;
 	public Gtk.ToolButton slides;
 	public Gtk.ToolButton fonts;
@@ -50,6 +52,8 @@ public class Ease.MainToolbar : Gtk.Toolbar
 		new_presentation = new Gtk.ToolButton.from_stock("gtk-new");
 		save = new Gtk.ToolButton.from_stock("gtk-save");
 		open = new Gtk.ToolButton.from_stock("gtk-open");
+		undo = new Gtk.ToolButton.from_stock("gtk-undo");
+		redo = new Gtk.ToolButton.from_stock("gtk-redo");
 		slides = new Gtk.ToolButton.from_stock("gtk-dnd-multiple");
 		inspector = new Gtk.ToolButton.from_stock("gtk-info");
 		colors = new Gtk.ToolButton.from_stock("gtk-select-color");
@@ -63,6 +67,9 @@ public class Ease.MainToolbar : Gtk.Toolbar
 		insert(open, -1);
 		insert(save, -1);
 		insert(new Gtk.SeparatorToolItem(), -1);
+		insert(undo, -1);
+		insert(redo, -1);
+		insert(new Gtk.SeparatorToolItem(), -1);
 		insert(slides, -1);
 		insert(inspector, -1);
 		insert(new Gtk.SeparatorToolItem(), -1);
diff --git a/src/libease/UndoActions.vala b/src/libease/UndoActions.vala
new file mode 100644
index 0000000..60a677b
--- /dev/null
+++ b/src/libease/UndoActions.vala
@@ -0,0 +1,70 @@
+/*  Ease, a GTK presentation application
+    Copyright (C) 2010 Nate Stedman
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * Abstract base class for undo actions.
+ *
+ * Subclasses should override apply() and add a constructor, as well as any
+ * needed data fields.
+ */
+public abstract class Ease.UndoAction : Object
+{
+	/**
+	 * Applies the { link UndoAction}.
+	 *
+	 * This method should be overriden by subclasses to undo the appropriate
+	 * action.
+	 */
+	public abstract void apply();
+}
+
+/**
+ * { link UndoAction} for moving or resizing an { link Actor}.
+ */
+public class Ease.MoveUndoAction : UndoAction
+{
+	private Actor actor;
+	private float x_pos;
+	private float y_pos;
+	private float width;
+	private float height;
+	
+	/**
+	 * Creates a new MoveUndoAction.
+	 *
+	 * @param actor The { link Actor} this applies to.
+	 * @param x The origin X position of the { link Actor}.
+	 * @param y The origin Y position of the { link Actor}.
+	 * @param w The origin width of the { link Actor}
+	 * @param h The origin height position of the { link Actor}
+	 */
+	public MoveUndoAction(Actor a, float x, float y, float w, float h)
+	{
+		actor = a;
+		x_pos = x;
+		y_pos = y;
+		width = w;
+		height = h;
+	}
+	
+	public override void apply()
+	{
+		actor.translate(x_pos - actor.x, y_pos - actor.y);
+		actor.resize(width - actor.width, height - actor.height, false);
+	}
+}
+
diff --git a/src/libease/UndoController.vala b/src/libease/UndoController.vala
new file mode 100644
index 0000000..1d0a545
--- /dev/null
+++ b/src/libease/UndoController.vala
@@ -0,0 +1,57 @@
+/*  Ease, a GTK presentation application
+    Copyright (C) 2010 Nate Stedman
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * Controls undo and redo actions.
+ *
+ * Each { link EditorWindow} has an UndoController that manages undo actions.
+ */
+public class Ease.UndoController
+{
+	private Gee.LinkedList<UndoAction> undos;
+	
+	public UndoController()
+	{
+		undos = new Gee.LinkedList<UndoAction>();
+	}
+	
+	/**
+	 * Returns true if there is an action available to undo.
+	 */
+	public bool can_undo()
+	{
+		return undos.size > 0;
+	}
+	
+	/**
+	 * Undoes the first available { link UndoAction}.
+	 */
+	public void undo()
+	{
+		undos.poll_head().apply();
+	}
+	
+	/**
+	 * Adds a new { link UndoAction} as the first action.
+	 *
+	 * @param action The new { link UndoAction}.
+	 */
+	public void add_action(UndoAction action)
+	{
+		undos.offer_head(action);
+	}
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]