From 0e8e2b3ee188e7c1e54b8f9c6e8781ffdc501906 Mon Sep 17 00:00:00 2001 From: Ian C Date: Tue, 7 Jul 2020 20:29:13 +0000 Subject: Added undo. --- SpriteEd/AppDelegate.cs | 15 ++++-- SpriteEd/NSSpriteEdit.cs | 75 +++++++++++++++++++++++------ SpriteEd/NSSpriteEditWindowDelegate.cs | 86 ++++++++++++++++++++++++++++++++++ SpriteEd/Sprite.cs | 12 ++++- SpriteEd/SpriteEd.csproj | 1 + SpriteEd/ViewController.cs | 22 ++++++++- 6 files changed, 190 insertions(+), 21 deletions(-) create mode 100644 SpriteEd/NSSpriteEditWindowDelegate.cs diff --git a/SpriteEd/AppDelegate.cs b/SpriteEd/AppDelegate.cs index eb40bd7..3756e70 100644 --- a/SpriteEd/AppDelegate.cs +++ b/SpriteEd/AppDelegate.cs @@ -38,6 +38,15 @@ namespace SpriteEd // Insert code here to tear down your application } + private ViewController ViewController + { + get + { + NSWindowController controller = NSApplication.SharedApplication.KeyWindow.WindowController as NSWindowController; + return controller.ContentViewController as ViewController; + } + } + [Export("newDocument:")] private void OnNewDocument(NSObject sender) { @@ -46,8 +55,7 @@ namespace SpriteEd [Export("saveDocumentAs:")] private void OnSaveDocumentAs(NSObject sender) { - NSWindowController controller = NSApplication.SharedApplication.KeyWindow.WindowController as NSWindowController; - ViewController view = controller.ContentViewController as ViewController; + ViewController view = ViewController; NSSavePanel fsel = new NSSavePanel(); @@ -75,8 +83,7 @@ namespace SpriteEd [Export("saveDocument:")] private void OnSaveDocument(NSObject sender) { - NSWindowController controller = NSApplication.SharedApplication.KeyWindow.WindowController as NSWindowController; - ViewController view = controller.ContentViewController as ViewController; + ViewController view = ViewController; if (view.Untitled) { diff --git a/SpriteEd/NSSpriteEdit.cs b/SpriteEd/NSSpriteEdit.cs index f6067ee..f5d5dc5 100644 --- a/SpriteEd/NSSpriteEdit.cs +++ b/SpriteEd/NSSpriteEdit.cs @@ -20,6 +20,7 @@ using Foundation; using System.CodeDom.Compiler; using AppKit; using CoreGraphics; +using System.Collections.Generic; namespace SpriteEd { @@ -81,7 +82,7 @@ namespace SpriteEd } private Sprite m_sprite; - private Sprite m_undo; + private Stack m_undo; private uint m_sx; private uint m_sy; private uint m_ex; @@ -95,7 +96,7 @@ namespace SpriteEd set { m_sprite = value; - m_undo = new Sprite(m_sprite.Width, m_sprite.Height); + ClearUndo(); NeedsDisplay = true; } } @@ -157,8 +158,11 @@ namespace SpriteEd /// private void Init() { + m_undo = new Stack(); m_sx = uint.MaxValue; m_sy = uint.MaxValue; + m_ex = uint.MaxValue; + m_ey = uint.MaxValue; WantsLayer = true; LayerContentsRedrawPolicy = NSViewLayerContentsRedrawPolicy.OnSetNeedsDisplay; } @@ -213,20 +217,61 @@ namespace SpriteEd } } + private NSSpriteEditWindowDelegate Delegate + { + get + { + NSSpriteEditWindowDelegate del = null; + + if (Window != null && Window.Delegate != null) + { + del = Window.Delegate as NSSpriteEditWindowDelegate; + } + + return del; + } + } + /// /// Save the undo state. /// - private void SaveUndo() + private void SaveUndo(string action) { - m_undo.CopyFrom(m_sprite); + NSSpriteEditWindowDelegate del = Delegate; + + if (del != null) + { + m_undo.Push(new Sprite(m_sprite)); + del.UndoManager.SetActionName(action); + + // I think I should be able to put a Sprite instance for the target + // but this seems to cause a crash deep in the runtime. + // + del.UndoManager.RegisterUndo(this, Undo); + } + } + + private void ClearUndo() + { + NSSpriteEditWindowDelegate del = Delegate; + + if (del != null) + { + del.UndoManager.RemoveAllActions(); + m_undo.Clear(); + } } /// /// Undo the last change. /// - public void Undo() + /// Ignored. + public void Undo(NSObject ignored) { - m_sprite.CopyFrom(m_undo); + Sprite tmp = m_undo.Pop(); + + m_sprite.CopyFrom(tmp); + NeedsDisplay = true; } @@ -649,14 +694,14 @@ namespace SpriteEd case DrawingMode.Point: if (m_sprite[m_sx, m_sy] != Colour) { - SaveUndo(); + SaveUndo("draw points"); m_sprite[m_sx, m_sy] = Colour; NeedsDisplay = true; } break; case DrawingMode.FloodFill: - SaveUndo(); + SaveUndo("fill"); FloodFill((int)m_sx, (int)m_sy, m_sprite[m_sx, m_sy]); NeedsDisplay = true; break; @@ -710,37 +755,37 @@ namespace SpriteEd switch(Mode) { case DrawingMode.Line: - SaveUndo(); + SaveUndo("line"); DrawSpriteLine(null); break; case DrawingMode.Rect: - SaveUndo(); + SaveUndo("rectangle"); DrawSpriteRect(null, false); break; case DrawingMode.FilledRect: - SaveUndo(); + SaveUndo("filled rectangle"); DrawSpriteRect(null, true); break; case DrawingMode.Circle: - SaveUndo(); + SaveUndo("circle"); DrawSpriteEllipse(null, true, false); break; case DrawingMode.FilledCircle: - SaveUndo(); + SaveUndo("filled circle"); DrawSpriteEllipse(null, true, true); break; case DrawingMode.Ellipse: - SaveUndo(); + SaveUndo("ellipse"); DrawSpriteEllipse(null, false, false); break; case DrawingMode.FilledEllipse: - SaveUndo(); + SaveUndo("filled ellipse"); DrawSpriteEllipse(null, false, true); break; diff --git a/SpriteEd/NSSpriteEditWindowDelegate.cs b/SpriteEd/NSSpriteEditWindowDelegate.cs new file mode 100644 index 0000000..d0cf4e0 --- /dev/null +++ b/SpriteEd/NSSpriteEditWindowDelegate.cs @@ -0,0 +1,86 @@ +// SpriteEd - Simple sprite editor +// Copyright 2020 Ian Cowburn +// +// 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 . +// +using System; +using AppKit; +using Foundation; + +namespace SpriteEd +{ + public class NSSpriteEditWindowDelegate : NSWindowDelegate + { + private NSUndoManager m_manager; + + /// + /// Default constructor. + /// + public NSSpriteEditWindowDelegate() : base() + { + Init(); + } + + /// + /// Construct given handle. + /// + /// The handle. + public NSSpriteEditWindowDelegate(IntPtr handle) : base(handle) + { + Init(); + } + + /// + /// Initialise the delegate. + /// + private void Init() + { + m_manager = new NSUndoManager(); + } + + /// + /// Get the Undo Manager. + /// + public NSUndoManager UndoManager + { + get + { + return m_manager; + } + } + + /// + /// Override windowWillReturnUndoManager. + /// + /// The window. + /// The Undo Manager. + [Export("windowWillReturnUndoManager:")] + public override NSUndoManager WillReturnUndoManager(NSWindow window) + { + return UndoManager; + } + + /// + /// Get the current ViewController. + /// + private ViewController ViewController + { + get + { + NSWindowController controller = NSApplication.SharedApplication.KeyWindow.WindowController as NSWindowController; + return controller.ContentViewController as ViewController; + } + } + } +} diff --git a/SpriteEd/Sprite.cs b/SpriteEd/Sprite.cs index c3da98a..024820c 100644 --- a/SpriteEd/Sprite.cs +++ b/SpriteEd/Sprite.cs @@ -16,13 +16,14 @@ // using System; using System.IO; +using Foundation; namespace SpriteEd { /// /// Represents a sprite. /// - public class Sprite + public class Sprite : NSObject { private uint[,] m_data; @@ -48,6 +49,15 @@ namespace SpriteEd m_data = new uint[width, height]; } + /// + /// Create a sprite from the passed sprite. + /// + /// The sprite to copy. + public Sprite(Sprite other) + { + CopyFrom(other); + } + /// /// Set/get a pixel value in the sprite. /// diff --git a/SpriteEd/SpriteEd.csproj b/SpriteEd/SpriteEd.csproj index 1fa7dc2..b8b98bd 100644 --- a/SpriteEd/SpriteEd.csproj +++ b/SpriteEd/SpriteEd.csproj @@ -88,6 +88,7 @@ + diff --git a/SpriteEd/ViewController.cs b/SpriteEd/ViewController.cs index 12a503f..43fdc64 100644 --- a/SpriteEd/ViewController.cs +++ b/SpriteEd/ViewController.cs @@ -24,6 +24,7 @@ namespace SpriteEd { private SpriteSet m_SpriteSet; private NSUrl m_Url; + private static int m_Untitled = 1; public ViewController(IntPtr handle) : base(handle) { @@ -37,12 +38,31 @@ namespace SpriteEd palette[0] = new Colour(0, 0, 0); palette[1] = new Colour(255, 255, 255); - Title = "Untitled"; Untitled = true; SpriteSet = new SpriteSet(SpriteSet.SetType.C64CharacterSet, 8, 8, palette, false, false, CodePoints.C64); } + public override void ViewDidAppear() + { + base.ViewDidAppear(); + + View.Window.Delegate = new NSSpriteEditWindowDelegate(); + + if (Untitled) + { + if (m_Untitled == 1) + { + View.Window.Title = "Untitled"; + m_Untitled++; + } + else + { + View.Window.Title = String.Format("Untitled {0}", m_Untitled++); + } + } + } + public override NSObject RepresentedObject { get -- cgit v1.2.3