added undo/redo

This commit is contained in:
codeimp 2007-11-12 22:43:01 +00:00
parent e0bc9dae58
commit e549691619
24 changed files with 1020 additions and 504 deletions

BIN
Resources/Icons/Redo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

BIN
Resources/Icons/Undo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

View file

@ -65,6 +65,9 @@
<Compile Include="Editing\LinedefsMode.cs" />
<Compile Include="Editing\SectorsMode.cs" />
<Compile Include="Editing\ThingsMode.cs" />
<Compile Include="Editing\UndoGroup.cs" />
<Compile Include="Editing\UndoManager.cs" />
<Compile Include="Editing\UndoSnapshot.cs" />
<Compile Include="Editing\VerticesMode.cs" />
<Compile Include="Editing\ClassicMode.cs" />
<Compile Include="Controls\ActionDelegate.cs" />
@ -281,6 +284,8 @@
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Builder.ico" />
<None Include="Resources\Redo.png" />
<None Include="Resources\Undo.png" />
<None Include="Resources\Grid2.png" />
<None Include="Resources\Hourglass.png" />
<None Include="Resources\Filter.png" />

View file

@ -46,6 +46,9 @@ namespace CodeImp.DoomBuilder.Editing
#region ================== Variables
// Undo ticket
private int undoticket;
// Mouse position on map where dragging started
protected Vector2D dragstartmappos;
@ -70,6 +73,9 @@ namespace CodeImp.DoomBuilder.Editing
this.dragitem = dragitem;
this.dragstartmappos = dragstartmappos;
// Make undo
undoticket = General.Map.UndoRedo.CreateUndo("drag vertices", UndoGroup.None, 0, false);
// Make old positions list
// We will use this as reference to move the vertices, or to move them back on cancel
oldpositions = new List<Vector2D>(General.Map.Selection.Vertices.Count);
@ -101,6 +107,9 @@ namespace CodeImp.DoomBuilder.Editing
{
int i = 0;
// Withdraw undo
General.Map.UndoRedo.WithdrawUndo(undoticket);
// Move geometry back to original position
foreach(Vertex v in General.Map.Selection.Vertices)
{
@ -138,7 +147,6 @@ namespace CodeImp.DoomBuilder.Editing
// When not cancelled
if(!cancelled)
{
// TODO: Merge geometry

View file

@ -0,0 +1,39 @@
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* 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.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Map;
#endregion
namespace CodeImp.DoomBuilder.Editing
{
public enum UndoGroup : int
{
None = 0,
FloorTextureChange = 1,
CeilingTextureChange = 2
}
}

View file

@ -0,0 +1,241 @@
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* 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.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Interface;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using System.Diagnostics;
using CodeImp.DoomBuilder.Controls;
#endregion
namespace CodeImp.DoomBuilder.Editing
{
public class UndoManager : IDisposable
{
#region ================== Constants
#endregion
#region ================== Variables
// Undo and redo stacks
private Stack<UndoSnapshot> undos;
private Stack<UndoSnapshot> redos;
// Grouping
private UndoGroup lastgroup;
private int lastgrouptag;
// Unique tickets
private int ticketid;
// Disposing
private bool isdisposed = false;
#endregion
#region ================== Properties
public UndoSnapshot NextUndo { get { if(undos.Count > 0) return undos.Peek(); else return null; } }
public UndoSnapshot NextRedo { get { if(redos.Count > 0) return redos.Peek(); else return null; } }
public bool IsDisposed { get { return isdisposed; } }
#endregion
#region ================== Constructor / Disposer
// Constructor
public UndoManager()
{
// Initialize
ticketid = 1;
undos = new Stack<UndoSnapshot>();
redos = new Stack<UndoSnapshot>();
// Bind any methods
ActionAttribute.BindMethods(this);
// We have no destructor
GC.SuppressFinalize(this);
}
// Diposer
public void Dispose()
{
// Not already disposed?
if(!isdisposed)
{
// Unbind any methods
ActionAttribute.UnbindMethods(this);
// Clean up
ClearUndos();
ClearRedos();
// Done
isdisposed = true;
}
}
#endregion
#region ================== Private Methods
// This clears the redos
private void ClearRedos()
{
// Dispose all redos
foreach(UndoSnapshot u in redos) u.map.Dispose();
redos.Clear();
}
// This clears the undos
private void ClearUndos()
{
// Dispose all undos
foreach(UndoSnapshot u in undos) u.map.Dispose();
undos.Clear();
}
#endregion
#region ================== Public Methods
// This makes an undo and returns the unique ticket id
public int CreateUndo(string description, UndoGroup group, int grouptag, bool allow3dchange)
{
UndoSnapshot u;
// Not the same as previous group?
if((group == UndoGroup.None) ||
(group != lastgroup) ||
(grouptag != lastgrouptag))
{
// Next ticket id
if(++ticketid == int.MaxValue) ticketid = 1;
// Make a snapshot
u = new UndoSnapshot(description, allow3dchange, General.Map.Map.Clone(), ticketid);
// Put it on the stack
undos.Push(u);
// Clear all redos
redos.Clear();
// Keep grouping info
lastgroup = group;
lastgrouptag = grouptag;
// Update
General.MainWindow.UpdateInterface();
// Done
return ticketid;
}
else
{
return -1;
}
}
// This removes a previously made undo
public void WithdrawUndo(int ticket)
{
// Anything to undo?
if(undos.Count > 0)
{
// Check if the ticket id matches
if(ticket == undos.Peek().ticketid)
{
// Remove the last made undo
undos.Pop();
// Update
General.MainWindow.UpdateInterface();
}
}
}
// This performs an undo
[Action("undo")]
public void PerformUndo()
{
UndoSnapshot u, r;
// Anything to undo?
if(undos.Count > 0)
{
// Get undo snapshot
u = undos.Pop();
// Make a snapshot for redo
r = new UndoSnapshot(u, General.Map.Map.Clone());
// Put it on the stack
redos.Push(r);
// Change map set
General.Map.ChangeMapSet(u.map);
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
}
}
// This performs a redo
[Action("redo")]
public void PerformRedo()
{
UndoSnapshot u, r;
// Anything to redo?
if(redos.Count > 0)
{
// Get redo snapshot
r = redos.Pop();
// Make a snapshot for undo
u = new UndoSnapshot(r, General.Map.Map.Clone());
// Put it on the stack
undos.Push(u);
// Change map set
General.Map.ChangeMapSet(r.map);
// Update
General.MainWindow.RedrawDisplay();
General.MainWindow.UpdateInterface();
}
}
#endregion
}
}

View file

@ -0,0 +1,63 @@
#region ================== Copyright (c) 2007 Pascal vd Heiden
/*
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
* This program is released under GNU General Public License
*
* 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.
*
*/
#endregion
#region ================== Namespaces
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using CodeImp.DoomBuilder.Interface;
using CodeImp.DoomBuilder.IO;
using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using System.Diagnostics;
using CodeImp.DoomBuilder.Controls;
#endregion
namespace CodeImp.DoomBuilder.Editing
{
public class UndoSnapshot
{
public MapSet map;
public string description;
public bool allow3dchange; // True when allowed to change in 3D mode
public int ticketid; // For safe withdrawing
// Constructor
public UndoSnapshot(string description, bool allow3dchange, MapSet map, int ticketid)
{
this.ticketid = ticketid;
this.description = description;
this.allow3dchange = allow3dchange;
this.map = map;
}
// Constructor
public UndoSnapshot(UndoSnapshot info, MapSet map)
{
this.ticketid = info.ticketid;
this.description = info.description;
this.allow3dchange = info.allow3dchange;
this.map = map;
}
}
}

View file

@ -77,6 +77,7 @@ namespace CodeImp.DoomBuilder
private WAD tempwad;
private MapSelection selection;
private GridSetup grid;
private UndoManager undoredo;
// Disposing
private bool isdisposed = false;
@ -100,6 +101,7 @@ namespace CodeImp.DoomBuilder
public GameConfiguration Config { get { return config; } }
public MapSelection Selection { get { return selection; } }
public GridSetup Grid { get { return grid; } }
public UndoManager UndoRedo { get { return undoredo; } }
#endregion
@ -114,6 +116,8 @@ namespace CodeImp.DoomBuilder
// Basic objects
grid = new GridSetup();
selection = new MapSelection();
undoredo = new UndoManager();
}
// Diposer
@ -130,6 +134,7 @@ namespace CodeImp.DoomBuilder
// Basic objects
if(selection != null) selection.Dispose();
if(undoredo != null) undoredo.Dispose();
// Dispose
General.WriteLogLine("Unloading data resources...");
@ -886,6 +891,18 @@ namespace CodeImp.DoomBuilder
#region ================== Methods
// This sets a new mapset for editing
public void ChangeMapSet(MapSet newmap)
{
// Can't have a selection in an old map set
selection.ClearAll();
// Apply
map.Dispose();
map = newmap;
map.Update();
}
// This reloads resources
[Action("reloadresources")]
public void ReloadResources()

File diff suppressed because it is too large Load diff

View file

@ -865,6 +865,20 @@ namespace CodeImp.DoomBuilder.Interface
itemlinedefsmode.Enabled = (General.Map != null);
itemsectorsmode.Enabled = (General.Map != null);
itemthingsmode.Enabled = (General.Map != null);
itemundo.Enabled = (General.Map != null) && (General.Map.UndoRedo.NextUndo != null);
itemredo.Enabled = (General.Map != null) && (General.Map.UndoRedo.NextRedo != null);
// Determine undo description
if(itemundo.Enabled)
itemundo.Text = "Undo " + General.Map.UndoRedo.NextUndo.description;
else
itemundo.Text = "Undo";
// Determine redo description
if(itemredo.Enabled)
itemredo.Text = "Redo " + General.Map.UndoRedo.NextRedo.description;
else
itemredo.Text = "Redo";
// Toolbar icons
buttonmapoptions.Enabled = (General.Map != null);
@ -872,6 +886,10 @@ namespace CodeImp.DoomBuilder.Interface
buttonlinedefsmode.Enabled = (General.Map != null);
buttonsectorsmode.Enabled = (General.Map != null);
buttonthingsmode.Enabled = (General.Map != null);
buttonundo.Enabled = itemundo.Enabled;
buttonredo.Enabled = itemredo.Enabled;
buttonundo.ToolTipText = itemundo.Text;
buttonredo.ToolTipText = itemredo.Text;
}
#endregion

View file

@ -147,10 +147,7 @@
<metadata name="toolStripSeparator7.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="toolStripMenuItem4.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="toolStripSeparator2.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<metadata name="toolStripMenuItem5.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="menumain.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
@ -165,12 +162,21 @@
<metadata name="toolbar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>121, 17</value>
</metadata>
<metadata name="toolStripSeparator10.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="statusbar.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="statusbar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>207, 17</value>
</metadata>
<metadata name="toolStripMenuItem4.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="toolStripSeparator2.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>False</value>
</metadata>
<metadata name="panelinfo.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>

View file

@ -29,7 +29,7 @@ using SlimDX.Direct3D;
namespace CodeImp.DoomBuilder.Map
{
public class Linedef : IDisposable
public sealed class Linedef : IDisposable
{
#region ================== Constants
@ -155,6 +155,17 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Management
// This copies all properties to another line
public void CopyPropertiesTo(Linedef l)
{
// Copy properties
l.action = action;
l.args = (byte[])args.Clone();
l.flags = flags;
l.tag = tag;
l.updateneeded = true;
}
// This attaches a sidedef on the front
public void AttachFront(Sidedef s)
{
@ -229,17 +240,6 @@ namespace CodeImp.DoomBuilder.Map
updateneeded = true;
}
// This copies all properties to another line
public void CopyPropertiesTo(Linedef l)
{
// Copy properties
l.action = action;
l.args = (byte[])args.Clone();
l.flags = flags;
l.tag = tag;
l.updateneeded = true;
}
#endregion
#region ================== Methods

View file

@ -29,7 +29,7 @@ using CodeImp.DoomBuilder.Data;
namespace CodeImp.DoomBuilder.Map
{
public class MapOptions
public sealed class MapOptions
{
#region ================== Constants

View file

@ -27,7 +27,7 @@ using CodeImp.DoomBuilder.Geometry;
namespace CodeImp.DoomBuilder.Map
{
public class MapSelection : IDisposable
public sealed class MapSelection : IDisposable
{
#region ================== Constants

View file

@ -31,7 +31,7 @@ using System.Drawing;
namespace CodeImp.DoomBuilder.Map
{
public class MapSet : IDisposable
public sealed class MapSet : IDisposable
{
#region ================== Variables
@ -128,6 +128,10 @@ namespace CodeImp.DoomBuilder.Map
Dictionary<Linedef, Linedef> linedeflink = new Dictionary<Linedef, Linedef>(linedefs.Count);
Dictionary<Sector, Sector> sectorlink = new Dictionary<Sector, Sector>(sectors.Count);
// TODO: Try making this faster by giving each element that
// requires a lookup (vertex/linedef/sector) a reference to
// its clone and remove those references after cloning.
// Create the map set
MapSet newset = new MapSet();

View file

@ -27,7 +27,7 @@ using CodeImp.DoomBuilder.IO;
namespace CodeImp.DoomBuilder.Map
{
public class Sector : IDisposable
public sealed class Sector : IDisposable
{
#region ================== Constants
@ -128,6 +128,21 @@ namespace CodeImp.DoomBuilder.Map
#region ================== Management
// This copies all properties to another sector
public void CopyPropertiesTo(Sector s)
{
// Copy properties
s.ceilheight = ceilheight;
s.ceiltexname = ceiltexname;
s.longceiltexname = longceiltexname;
s.floorheight = floorheight;
s.floortexname = floortexname;
s.longfloortexname = longfloortexname;
s.effect = effect;
s.tag = tag;
s.brightness = brightness;
}
// This attaches a sidedef and returns the listitem
public LinkedListNode<Sidedef> AttachSidedef(Sidedef sd) { return sidedefs.AddLast(sd); }
@ -155,19 +170,6 @@ namespace CodeImp.DoomBuilder.Map
// This detaches a thing
public void DetachThing(LinkedListNode<Thing> l) { if(!isdisposed) things.Remove(l); }
// This copies all properties to another sector
public void CopyPropertiesTo(Sector s)
{
// Copy properties
s.ceilheight = ceilheight;
s.SetCeilTexture(ceiltexname);
s.floorheight = floorheight;
s.SetFloorTexture(floortexname);
s.effect = effect;
s.tag = tag;
s.brightness = brightness;
}
#endregion
#region ================== Changes

View file

@ -27,7 +27,7 @@ using CodeImp.DoomBuilder.IO;
namespace CodeImp.DoomBuilder.Map
{
public class Sidedef : IDisposable
public sealed class Sidedef : IDisposable
{
#region ================== Constants
@ -140,9 +140,12 @@ namespace CodeImp.DoomBuilder.Map
// Copy properties
s.offsetx = offsetx;
s.offsety = offsety;
s.SetTextureHigh(texnamehigh);
s.SetTextureMid(texnamelow);
s.SetTextureLow(texnamemid);
s.texnamehigh = texnamehigh;
s.texnamemid = texnamemid;
s.texnamelow = texnamelow;
s.longtexnamehigh = longtexnamehigh;
s.longtexnamemid = longtexnamemid;
s.longtexnamelow = longtexnamelow;
}
#endregion

View file

@ -30,7 +30,7 @@ using System.Drawing;
namespace CodeImp.DoomBuilder.Map
{
public class Thing : IDisposable
public sealed class Thing : IDisposable
{
#region ================== Constants
@ -63,7 +63,7 @@ namespace CodeImp.DoomBuilder.Map
// Configuration
private float size;
private PixelColor color;
private float iconoffset;
private float iconoffset; // Arrow or dot coordinate offset on the texture
// Selections
private int selected;
@ -143,10 +143,13 @@ namespace CodeImp.DoomBuilder.Map
t.flags = flags;
t.tag = tag;
t.action = action;
t.args = EMPTY_ARGS;
t.x = x;
t.y = y;
t.zoffset = zoffset;
t.args = EMPTY_ARGS;
t.size = size;
t.color = color;
t.iconoffset = iconoffset;
args.CopyTo(t.args, 0);
}

View file

@ -30,7 +30,7 @@ using System.Drawing;
namespace CodeImp.DoomBuilder.Map
{
public class Vertex : IDisposable
public sealed class Vertex : IDisposable
{
#region ================== Constants

View file

@ -123,6 +123,13 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
internal static System.Drawing.Bitmap Redo {
get {
object obj = ResourceManager.GetObject("Redo", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
internal static System.Drawing.Bitmap SaveMap {
get {
object obj = ResourceManager.GetObject("SaveMap", resourceCulture);
@ -179,6 +186,13 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
internal static System.Drawing.Bitmap Undo {
get {
object obj = ResourceManager.GetObject("Undo", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
internal static System.Drawing.Bitmap UnknownImage {
get {
object obj = ResourceManager.GetObject("UnknownImage", resourceCulture);

View file

@ -142,6 +142,9 @@
<data name="NewMap" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NewMap2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Undo" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Undo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ColorPick" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ColorPick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -151,6 +154,9 @@
<data name="UnknownImage" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\UnknownImage.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Grid2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Grid2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="OpenMap" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\OpenMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -175,7 +181,7 @@
<data name="File" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NewMap.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Grid2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Grid2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<data name="Redo" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Redo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View file

@ -211,3 +211,21 @@ gridsetup
allowmouse = false;
allowscroll = false;
}
undo
{
title = "Edit: Undo";
description = "Restores the current map as it was before last action(s) performed.";
allowkeys = true;
allowmouse = false;
allowscroll = false;
}
redo
{
title = "Edit: Redo";
description = "Repeates the action(s) performed before Undo was used.";
allowkeys = true;
allowmouse = false;
allowscroll = false;
}

BIN
Source/Resources/Redo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

BIN
Source/Resources/Undo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B