From 05c13a15e210000d6750447918f6daf01f70869f Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 12:23:01 +0200
Subject: [PATCH 01/15] Added alt-shortcuts to main context menu

---
 ReClass.NET/Forms/MainForm.Designer.cs | 32 +++++++++++++-------------
 ReClass.NET/Forms/MainForm.resx        |  2 +-
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index e2b2a199..7b2135f7 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -410,7 +410,7 @@ private void InitializeComponent()
 			this.changeTypeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Exchange_Button;
 			this.changeTypeToolStripMenuItem.Name = "changeTypeToolStripMenuItem";
 			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.changeTypeToolStripMenuItem.Text = "Change Type";
+			this.changeTypeToolStripMenuItem.Text = "&Change Type";
 			// 
 			// addBytesToolStripMenuItem
 			// 
@@ -426,7 +426,7 @@ private void InitializeComponent()
 			this.addBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Add_Bytes_X;
 			this.addBytesToolStripMenuItem.Name = "addBytesToolStripMenuItem";
 			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.addBytesToolStripMenuItem.Text = "Add Bytes";
+			this.addBytesToolStripMenuItem.Text = "&Add Bytes";
 			// 
 			// integerToolStripMenuItem1
 			// 
@@ -513,7 +513,7 @@ private void InitializeComponent()
 			this.insertBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Insert_Bytes_X;
 			this.insertBytesToolStripMenuItem.Name = "insertBytesToolStripMenuItem";
 			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.insertBytesToolStripMenuItem.Text = "Insert Bytes";
+			this.insertBytesToolStripMenuItem.Text = "&Insert Bytes";
 			// 
 			// integerToolStripMenuItem8
 			// 
@@ -596,7 +596,7 @@ private void InitializeComponent()
 			this.createClassFromNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Class_Add;
 			this.createClassFromNodesToolStripMenuItem.Name = "createClassFromNodesToolStripMenuItem";
 			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.createClassFromNodesToolStripMenuItem.Text = "Create Class from Nodes";
+			this.createClassFromNodesToolStripMenuItem.Text = "C&reate Class from Nodes";
 			this.createClassFromNodesToolStripMenuItem.Click += new System.EventHandler(this.createClassFromNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator13
@@ -609,7 +609,7 @@ private void InitializeComponent()
 			this.dissectNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Camera;
 			this.dissectNodesToolStripMenuItem.Name = "dissectNodesToolStripMenuItem";
 			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.dissectNodesToolStripMenuItem.Text = "Dissect Node(s)";
+			this.dissectNodesToolStripMenuItem.Text = "&Dissect Node(s)";
 			this.dissectNodesToolStripMenuItem.Click += new System.EventHandler(this.dissectNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator9
@@ -622,7 +622,7 @@ private void InitializeComponent()
 			this.searchForEqualValuesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.searchForEqualValuesToolStripMenuItem.Name = "searchForEqualValuesToolStripMenuItem";
 			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.searchForEqualValuesToolStripMenuItem.Text = "Search for equal values...";
+			this.searchForEqualValuesToolStripMenuItem.Text = "&Search for equal values...";
 			this.searchForEqualValuesToolStripMenuItem.Click += new System.EventHandler(this.searchForEqualValuesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator15
@@ -635,7 +635,7 @@ private void InitializeComponent()
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Access;
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Name = "findOutWhatAccessesThisAddressToolStripMenuItem";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "Find out what accesses this address...";
+			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "&Find out what accesses this address...";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatAccessesThisAddressToolStripMenuItem_Click);
 			// 
 			// findOutWhatWritesToThisAddressToolStripMenuItem
@@ -643,7 +643,7 @@ private void InitializeComponent()
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Write;
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Name = "findOutWhatWritesToThisAddressToolStripMenuItem";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what writes to this address...";
+			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what &writes to this address...";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatWritesToThisAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator14
@@ -656,7 +656,7 @@ private void InitializeComponent()
 			this.copyNodeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyNodeToolStripMenuItem.Name = "copyNodeToolStripMenuItem";
 			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.copyNodeToolStripMenuItem.Text = "Copy Node(s)";
+			this.copyNodeToolStripMenuItem.Text = "C&opy Node(s)";
 			this.copyNodeToolStripMenuItem.Click += new System.EventHandler(this.copyNodeToolStripMenuItem_Click);
 			// 
 			// pasteNodesToolStripMenuItem
@@ -664,7 +664,7 @@ private void InitializeComponent()
 			this.pasteNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Paste;
 			this.pasteNodesToolStripMenuItem.Name = "pasteNodesToolStripMenuItem";
 			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.pasteNodesToolStripMenuItem.Text = "Paste Node(s)";
+			this.pasteNodesToolStripMenuItem.Text = "&Paste Node(s)";
 			this.pasteNodesToolStripMenuItem.Click += new System.EventHandler(this.pasteNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator10
@@ -677,7 +677,7 @@ private void InitializeComponent()
 			this.removeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Delete;
 			this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
 			this.removeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.removeToolStripMenuItem.Text = "Remove Node(s)";
+			this.removeToolStripMenuItem.Text = "&Remove Node(s)";
 			this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator12
@@ -690,7 +690,7 @@ private void InitializeComponent()
 			this.hideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.hideNodesToolStripMenuItem.Name = "hideNodesToolStripMenuItem";
 			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.hideNodesToolStripMenuItem.Text = "Hide selected Node(s)";
+			this.hideNodesToolStripMenuItem.Text = "&Hide selected Node(s)";
 			this.hideNodesToolStripMenuItem.Click += new System.EventHandler(this.hideNodesToolStripMenuItem_Click);
 			// 
 			// unhideNodesToolStripMenuItem
@@ -702,7 +702,7 @@ private void InitializeComponent()
 			this.unhideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.unhideNodesToolStripMenuItem.Name = "unhideNodesToolStripMenuItem";
 			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.unhideNodesToolStripMenuItem.Text = "Unhide...";
+			this.unhideNodesToolStripMenuItem.Text = "&Unhide...";
 			// 
 			// unhideChildNodesToolStripMenuItem
 			// 
@@ -738,7 +738,7 @@ private void InitializeComponent()
 			this.copyAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyAddressToolStripMenuItem.Name = "copyAddressToolStripMenuItem";
 			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.copyAddressToolStripMenuItem.Text = "Copy Address";
+			this.copyAddressToolStripMenuItem.Text = "Cop&y Address";
 			this.copyAddressToolStripMenuItem.Click += new System.EventHandler(this.copyAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator11
@@ -751,7 +751,7 @@ private void InitializeComponent()
 			this.showCodeOfClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Code_Cpp;
 			this.showCodeOfClassToolStripMenuItem.Name = "showCodeOfClassToolStripMenuItem";
 			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.showCodeOfClassToolStripMenuItem.Text = "Show C++ Code of Class";
+			this.showCodeOfClassToolStripMenuItem.Text = "Show C&++ Code of Class";
 			this.showCodeOfClassToolStripMenuItem.Click += new System.EventHandler(this.showCodeOfClassToolStripMenuItem_Click);
 			// 
 			// shrinkClassToolStripMenuItem
@@ -759,7 +759,7 @@ private void InitializeComponent()
 			this.shrinkClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Chart_Delete;
 			this.shrinkClassToolStripMenuItem.Name = "shrinkClassToolStripMenuItem";
 			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.shrinkClassToolStripMenuItem.Text = "Shrink Class";
+			this.shrinkClassToolStripMenuItem.Text = "Shri&nk Class";
 			this.shrinkClassToolStripMenuItem.Click += new System.EventHandler(this.shrinkClassToolStripMenuItem_Click);
 			// 
 			// toolStrip
diff --git a/ReClass.NET/Forms/MainForm.resx b/ReClass.NET/Forms/MainForm.resx
index c430dab3..0e88c503 100644
--- a/ReClass.NET/Forms/MainForm.resx
+++ b/ReClass.NET/Forms/MainForm.resx
@@ -206,6 +206,6 @@
 </value>
   </data>
   <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>42</value>
+    <value>104</value>
   </metadata>
 </root>
\ No newline at end of file

From e3660a7ab11dd9c203c39b62ef42b3a5c93883ca Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 14:28:17 +0200
Subject: [PATCH 02/15] Defined various shortcut keys on the node type menu
 items. Changed toolbar button to toolbar menu item so it can have a shortcut
 too.

---
 ReClass.NET/Forms/MainForm.Designer.cs |  1 +
 ReClass.NET/Settings.cs                | 36 +++++++++++++++++++++++++-
 ReClass.NET/UI/NodeTypesBuilder.cs     | 18 ++++++++-----
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index 7b2135f7..80cf31e4 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -1377,6 +1377,7 @@ private void InitializeComponent()
 			this.Controls.Add(this.toolStrip);
 			this.Controls.Add(this.statusStrip);
 			this.Controls.Add(this.mainMenuStrip);
+			this.KeyPreview = true;
 			this.MainMenuStrip = this.mainMenuStrip;
 			this.MinimumSize = new System.Drawing.Size(200, 100);
 			this.Name = "MainForm";
diff --git a/ReClass.NET/Settings.cs b/ReClass.NET/Settings.cs
index b5d9268b..16f0abb1 100644
--- a/ReClass.NET/Settings.cs
+++ b/ReClass.NET/Settings.cs
@@ -1,11 +1,39 @@
-using System.Drawing;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
 using System.Text;
+using System.Windows.Forms;
+using ReClassNET.Nodes;
 using ReClassNET.Util;
 
 namespace ReClassNET
 {
 	public class Settings
 	{
+		private readonly Dictionary<Type, Keys> _shortcutKeyPerNode;
+
+		public Settings()
+		{
+			_shortcutKeyPerNode = new Dictionary<Type, Keys>
+								  {
+									  { typeof(Hex64Node), Keys.Control | Keys.Shift | Keys.D6 },
+									  { typeof(ClassInstanceNode), Keys.Control | Keys.Shift | Keys.I },
+									  { typeof(FloatNode), Keys.Control | Keys.Shift | Keys.F },
+									  { typeof(Hex8Node), Keys.Control | Keys.Shift | Keys.B },
+									  { typeof(PointerNode), Keys.Control | Keys.Shift | Keys.P },
+									  { typeof(Vector2Node), Keys.Control | Keys.Shift | Keys.D2 },
+									  { typeof(Vector3Node), Keys.Control | Keys.Shift | Keys.D3 },
+									  { typeof(Vector4Node), Keys.Control | Keys.Shift | Keys.D4 },
+									  { typeof(VirtualMethodTableNode), Keys.Control | Keys.Shift | Keys.T },
+									  { typeof(BoolNode), Keys.Control | Keys.Shift | Keys.O },
+									  { typeof(EnumNode), Keys.Control | Keys.Shift | Keys.E },
+									  { typeof(Int32Node), Keys.Control | Keys.Shift | Keys.N }
+								  };
+
+			// Define more here.
+		}
+
+		
 		// Application Settings
 
 		public string LastProcess { get; set; } = string.Empty;
@@ -76,6 +104,12 @@ public class Settings
 
 		public CustomDataMap CustomData { get; } = new CustomDataMap();
 
+
+		public Keys GetShortcutKeyForNodeType(Type nodeType)
+		{
+			return !_shortcutKeyPerNode.TryGetValue(nodeType, out var shortcutKeys) ? Keys.None : shortcutKeys;
+		}
+
 		public Settings Clone() => MemberwiseClone() as Settings;
 	}
 }
diff --git a/ReClass.NET/UI/NodeTypesBuilder.cs b/ReClass.NET/UI/NodeTypesBuilder.cs
index 8d519022..b0badd25 100644
--- a/ReClass.NET/UI/NodeTypesBuilder.cs
+++ b/ReClass.NET/UI/NodeTypesBuilder.cs
@@ -57,14 +57,15 @@ public static IEnumerable<ToolStripItem> CreateToolStripButtons(Action<Type> han
 
 			return CreateToolStripItems(t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
-				var item = new TypeToolStripButton
+				var item = new TypeToolStripMenuItem
 				{
 					Value = t,
 					ToolTipText = label,
 					DisplayStyle = ToolStripItemDisplayStyle.Image,
-					Image = icon
+					Image = icon,
+					ShortcutKeys = shortcutKeys,
 				};
 				item.Click += clickHandler;
 				return item;
@@ -74,7 +75,7 @@ public static IEnumerable<ToolStripItem> CreateToolStripButtons(Action<Type> han
 				Image = p.Icon
 			}, t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
 				var item = new TypeToolStripMenuItem
 				{
@@ -95,13 +96,14 @@ public static IEnumerable<ToolStripItem> CreateToolStripMenuItems(Action<Type> h
 
 			var items = CreateToolStripItems(t =>
 			{
-				GetNodeInfoFromType(t, out var label, out var icon);
+				GetNodeInfoFromType(t, out var label, out var icon, out var shortcutKeys);
 
 				var item = new TypeToolStripMenuItem
 				{
 					Value = t,
 					Text = label,
-					Image = icon
+					Image = icon,
+					ShortcutKeys = shortcutKeys,
 				};
 				item.Click += clickHandler;
 				return item;
@@ -166,10 +168,12 @@ private static IEnumerable<ToolStripItem> CreateToolStripItems(Func<Type, ToolSt
 			return items;
 		}
 
-		private static void GetNodeInfoFromType(Type nodeType, out string label, out Image icon)
+		private static void GetNodeInfoFromType(Type nodeType, out string label, out Image icon, out Keys shortcutKeys)
 		{
 			Contract.Requires(nodeType != null);
 
+			shortcutKeys = Program.Settings.GetShortcutKeyForNodeType(nodeType);
+
 			var node = BaseNode.CreateInstanceFromType(nodeType, false);
 			if (node == null)
 			{

From 4d3ac22a960738cb8f0405d2353d72fc288a5a2e Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 14:57:10 +0200
Subject: [PATCH 03/15] Moved ReadFromBuffer to MemoryBuffer where it belongs,
 and it's now usable from different nodes. Changed VTable node so it always
 displays the RTTI information if available.

---
 ReClass.NET/Memory/MemoryBuffer.cs          |  7 +++++++
 ReClass.NET/Nodes/Hex64Node.cs              | 12 +++---------
 ReClass.NET/Nodes/VirtualMethodTableNode.cs | 19 +++++++++++++++++++
 3 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/ReClass.NET/Memory/MemoryBuffer.cs b/ReClass.NET/Memory/MemoryBuffer.cs
index e1b515a4..bde66ace 100644
--- a/ReClass.NET/Memory/MemoryBuffer.cs
+++ b/ReClass.NET/Memory/MemoryBuffer.cs
@@ -366,5 +366,12 @@ public bool HasChanged(int offset, int length)
 
 			return false;
 		}
+
+
+		public UInt64FloatDoubleData ReadFromBuffer(int offset) => new UInt64FloatDoubleData
+																   {
+																	   Raw1 = ReadInt32(offset),
+																	   Raw2 = ReadInt32(offset + sizeof(int))
+																   };
 	}
 }
diff --git a/ReClass.NET/Nodes/Hex64Node.cs b/ReClass.NET/Nodes/Hex64Node.cs
index d54f1e71..012859ef 100644
--- a/ReClass.NET/Nodes/Hex64Node.cs
+++ b/ReClass.NET/Nodes/Hex64Node.cs
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
 
 		public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.ReadFromBuffer(Offset);
 
 			address = value.IntPtr;
 
@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 
 		public override string GetToolTipText(HotSpot spot)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.ReadFromBuffer(Offset);
 
 			return $"Int64: {value.LongValue}\nUInt64: 0x{value.ULongValue:X016}\nFloat: {value.FloatValue:0.000}\nDouble: {value.DoubleValue:0.000}";
 		}
@@ -46,17 +46,11 @@ protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
 
-			var value = ReadFromBuffer(context.Memory, Offset);
+			var value = context.Memory.ReadFromBuffer(Offset);
 
 			x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
 
 			return x;
 		}
-
-		private static UInt64FloatDoubleData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt64FloatDoubleData
-		{
-			Raw1 = memory.ReadInt32(offset),
-			Raw2 = memory.ReadInt32(offset + sizeof(int))
-		};
 	}
 }
diff --git a/ReClass.NET/Nodes/VirtualMethodTableNode.cs b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
index 9e82ab40..3f58c3e5 100644
--- a/ReClass.NET/Nodes/VirtualMethodTableNode.cs
+++ b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
@@ -34,6 +34,25 @@ public override void Initialize()
 			}
 		}
 
+
+		protected override int AddComment(DrawContext context, int x, int y)
+		{
+			x = base.AddComment(context, x, y);
+			
+			if (context.Settings.ShowCommentRtti)
+			{
+				var addressFirstVTableFunction = context.Memory.ReadFromBuffer(Offset).IntPtr;
+				var rtti = context.Process.ReadRemoteRuntimeTypeInformation(addressFirstVTableFunction);
+				if (!string.IsNullOrEmpty(rtti))
+				{
+					x = AddText(context, x, y, context.Settings.OffsetColor, HotSpot.ReadOnlyId, rtti) + context.Font.Width;
+				}
+			}
+
+			return x;
+		}
+
+
 		public override Size Draw(DrawContext context, int x, int y)
 		{
 			if (IsHidden && !IsWrapped)

From 4d2f079049b61d83d391e618e04fc927de783c3c Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 15:15:56 +0200
Subject: [PATCH 04/15] Redefined some kb shortcuts, as ctrl-shift-c/v aren't
 used elsewhere

---
 ReClass.NET/Settings.cs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/ReClass.NET/Settings.cs b/ReClass.NET/Settings.cs
index 16f0abb1..8c0ec099 100644
--- a/ReClass.NET/Settings.cs
+++ b/ReClass.NET/Settings.cs
@@ -17,17 +17,17 @@ public Settings()
 			_shortcutKeyPerNode = new Dictionary<Type, Keys>
 								  {
 									  { typeof(Hex64Node), Keys.Control | Keys.Shift | Keys.D6 },
-									  { typeof(ClassInstanceNode), Keys.Control | Keys.Shift | Keys.I },
+									  { typeof(ClassInstanceNode), Keys.Control | Keys.Shift | Keys.C },
 									  { typeof(FloatNode), Keys.Control | Keys.Shift | Keys.F },
 									  { typeof(Hex8Node), Keys.Control | Keys.Shift | Keys.B },
 									  { typeof(PointerNode), Keys.Control | Keys.Shift | Keys.P },
 									  { typeof(Vector2Node), Keys.Control | Keys.Shift | Keys.D2 },
 									  { typeof(Vector3Node), Keys.Control | Keys.Shift | Keys.D3 },
 									  { typeof(Vector4Node), Keys.Control | Keys.Shift | Keys.D4 },
-									  { typeof(VirtualMethodTableNode), Keys.Control | Keys.Shift | Keys.T },
+									  { typeof(VirtualMethodTableNode), Keys.Control | Keys.Shift | Keys.V },
 									  { typeof(BoolNode), Keys.Control | Keys.Shift | Keys.O },
 									  { typeof(EnumNode), Keys.Control | Keys.Shift | Keys.E },
-									  { typeof(Int32Node), Keys.Control | Keys.Shift | Keys.N }
+									  { typeof(Int32Node), Keys.Control | Keys.Shift | Keys.I }
 								  };
 
 			// Define more here.

From 208454edf064e61c79a3c3ecbfef27c60210213a Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 19:26:55 +0200
Subject: [PATCH 05/15] Added a way to name a class after RTTI information
 associated with the class. This required some hairy work in a lot of places
 as the context menu wasn't usable on nested classes. It now is

---
 ReClass.NET/Controls/MemoryViewControl.cs     |  19 +++++
 ReClass.NET/Forms/MainForm.Designer.cs        |  65 +++++++++++-------
 ReClass.NET/Forms/MainForm.cs                 |  15 +++-
 ReClass.NET/Nodes/BaseContainerNode.cs        |   4 +-
 ReClass.NET/Nodes/BaseHexCommentNode.cs       |   8 ++-
 ReClass.NET/Nodes/BaseNode.cs                 |  13 +++-
 ReClass.NET/Nodes/ClassNode.cs                |  40 +++++++++++
 ReClass.NET/Nodes/PointerNode.cs              |  36 ++++++++++
 ReClass.NET/Nodes/VirtualMethodTableNode.cs   |  16 ++++-
 ReClass.NET/Properties/Resources.Designer.cs  |  14 +++-
 ReClass.NET/Properties/Resources.resx         |   3 +
 ReClass.NET/ReClass.NET.csproj                |   3 +
 .../Images/B16x16_Button_AutoName.png         | Bin 0 -> 383 bytes
 ReClass.NET/UI/HotSpot.cs                     |   2 +-
 14 files changed, 200 insertions(+), 38 deletions(-)
 create mode 100644 ReClass.NET/Resources/Images/B16x16_Button_AutoName.png

diff --git a/ReClass.NET/Controls/MemoryViewControl.cs b/ReClass.NET/Controls/MemoryViewControl.cs
index 64b8dfa4..1769f05a 100644
--- a/ReClass.NET/Controls/MemoryViewControl.cs
+++ b/ReClass.NET/Controls/MemoryViewControl.cs
@@ -704,5 +704,24 @@ public void Reset()
 
 			VerticalScroll.Value = VerticalScroll.Minimum;
 		}
+
+
+		public void AutoNameCurrentClassFromRTTI(ClassNode classNode)
+		{
+			var args = new DrawContextRequestEventArgs { Node = classNode };
+
+			var requestHandler = DrawContextRequested;
+			requestHandler?.Invoke(this, args);
+			var view = new DrawContext
+					   {
+						   Settings = args.Settings,
+						   Process = args.Process,
+						   Memory = args.Memory,
+						   CurrentTime = args.CurrentTime,
+						   Address = args.BaseAddress,
+						   Level = 0,
+					   };
+			classNode.AutoNameFromRTTI(view);
+		}
 	}
 }
diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index 80cf31e4..cb15cbe5 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -77,6 +77,7 @@ private void InitializeComponent()
 			this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
 			this.createClassFromNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
+			this.autoNameClassToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.dissectNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
 			this.searchForEqualValuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -382,6 +383,7 @@ private void InitializeComponent()
             this.toolStripSeparator8,
             this.createClassFromNodesToolStripMenuItem,
             this.toolStripSeparator13,
+            this.autoNameClassToolStripMenuItem,
             this.dissectNodesToolStripMenuItem,
             this.toolStripSeparator9,
             this.searchForEqualValuesToolStripMenuItem,
@@ -402,14 +404,14 @@ private void InitializeComponent()
             this.showCodeOfClassToolStripMenuItem,
             this.shrinkClassToolStripMenuItem});
 			this.selectedNodeContextMenuStrip.Name = "selectedNodeContextMenuStrip";
-			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 410);
+			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(296, 454);
 			this.selectedNodeContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.selectedNodeContextMenuStrip_Opening);
 			// 
 			// changeTypeToolStripMenuItem
 			// 
 			this.changeTypeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Exchange_Button;
 			this.changeTypeToolStripMenuItem.Name = "changeTypeToolStripMenuItem";
-			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.changeTypeToolStripMenuItem.Text = "&Change Type";
 			// 
 			// addBytesToolStripMenuItem
@@ -425,7 +427,7 @@ private void InitializeComponent()
             this.toolStripMenuItem1});
 			this.addBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Add_Bytes_X;
 			this.addBytesToolStripMenuItem.Name = "addBytesToolStripMenuItem";
-			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.addBytesToolStripMenuItem.Text = "&Add Bytes";
 			// 
 			// integerToolStripMenuItem1
@@ -512,7 +514,7 @@ private void InitializeComponent()
             this.toolStripMenuItem2});
 			this.insertBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Insert_Bytes_X;
 			this.insertBytesToolStripMenuItem.Name = "insertBytesToolStripMenuItem";
-			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.insertBytesToolStripMenuItem.Text = "&Insert Bytes";
 			// 
 			// integerToolStripMenuItem8
@@ -589,52 +591,62 @@ private void InitializeComponent()
 			// toolStripSeparator8
 			// 
 			this.toolStripSeparator8.Name = "toolStripSeparator8";
-			this.toolStripSeparator8.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator8.Size = new System.Drawing.Size(292, 6);
 			// 
 			// createClassFromNodesToolStripMenuItem
 			// 
 			this.createClassFromNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Class_Add;
 			this.createClassFromNodesToolStripMenuItem.Name = "createClassFromNodesToolStripMenuItem";
-			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.createClassFromNodesToolStripMenuItem.Text = "C&reate Class from Nodes";
 			this.createClassFromNodesToolStripMenuItem.Click += new System.EventHandler(this.createClassFromNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator13
 			// 
 			this.toolStripSeparator13.Name = "toolStripSeparator13";
-			this.toolStripSeparator13.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator13.Size = new System.Drawing.Size(292, 6);
+			// 
+			// autoNameClassToolStripMenuItem
+			// 
+			this.autoNameClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
+			this.autoNameClassToolStripMenuItem.Name = "autoNameClassToolStripMenuItem";
+			this.autoNameClassToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
+            | System.Windows.Forms.Keys.N)));
+			this.autoNameClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.autoNameClassToolStripMenuItem.Text = "Auto-Name Class from RTTI";
+			this.autoNameClassToolStripMenuItem.Click += new System.EventHandler(this.autoNameClassToolStripMenuItem_Click);
 			// 
 			// dissectNodesToolStripMenuItem
 			// 
 			this.dissectNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Camera;
 			this.dissectNodesToolStripMenuItem.Name = "dissectNodesToolStripMenuItem";
-			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.dissectNodesToolStripMenuItem.Text = "&Dissect Node(s)";
 			this.dissectNodesToolStripMenuItem.Click += new System.EventHandler(this.dissectNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator9
 			// 
 			this.toolStripSeparator9.Name = "toolStripSeparator9";
-			this.toolStripSeparator9.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator9.Size = new System.Drawing.Size(292, 6);
 			// 
 			// searchForEqualValuesToolStripMenuItem
 			// 
 			this.searchForEqualValuesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.searchForEqualValuesToolStripMenuItem.Name = "searchForEqualValuesToolStripMenuItem";
-			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.searchForEqualValuesToolStripMenuItem.Text = "&Search for equal values...";
 			this.searchForEqualValuesToolStripMenuItem.Click += new System.EventHandler(this.searchForEqualValuesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator15
 			// 
 			this.toolStripSeparator15.Name = "toolStripSeparator15";
-			this.toolStripSeparator15.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator15.Size = new System.Drawing.Size(292, 6);
 			// 
 			// findOutWhatAccessesThisAddressToolStripMenuItem
 			// 
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Access;
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Name = "findOutWhatAccessesThisAddressToolStripMenuItem";
-			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "&Find out what accesses this address...";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatAccessesThisAddressToolStripMenuItem_Click);
 			// 
@@ -642,20 +654,20 @@ private void InitializeComponent()
 			// 
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Write;
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Name = "findOutWhatWritesToThisAddressToolStripMenuItem";
-			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what &writes to this address...";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatWritesToThisAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator14
 			// 
 			this.toolStripSeparator14.Name = "toolStripSeparator14";
-			this.toolStripSeparator14.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator14.Size = new System.Drawing.Size(292, 6);
 			// 
 			// copyNodeToolStripMenuItem
 			// 
 			this.copyNodeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyNodeToolStripMenuItem.Name = "copyNodeToolStripMenuItem";
-			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.copyNodeToolStripMenuItem.Text = "C&opy Node(s)";
 			this.copyNodeToolStripMenuItem.Click += new System.EventHandler(this.copyNodeToolStripMenuItem_Click);
 			// 
@@ -663,33 +675,33 @@ private void InitializeComponent()
 			// 
 			this.pasteNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Paste;
 			this.pasteNodesToolStripMenuItem.Name = "pasteNodesToolStripMenuItem";
-			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.pasteNodesToolStripMenuItem.Text = "&Paste Node(s)";
 			this.pasteNodesToolStripMenuItem.Click += new System.EventHandler(this.pasteNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator10
 			// 
 			this.toolStripSeparator10.Name = "toolStripSeparator10";
-			this.toolStripSeparator10.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator10.Size = new System.Drawing.Size(292, 6);
 			// 
 			// removeToolStripMenuItem
 			// 
 			this.removeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Delete;
 			this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
-			this.removeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.removeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.removeToolStripMenuItem.Text = "&Remove Node(s)";
 			this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator12
 			// 
 			this.toolStripSeparator12.Name = "toolStripSeparator12";
-			this.toolStripSeparator12.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator12.Size = new System.Drawing.Size(292, 6);
 			// 
 			// hideNodesToolStripMenuItem
 			// 
 			this.hideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.hideNodesToolStripMenuItem.Name = "hideNodesToolStripMenuItem";
-			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.hideNodesToolStripMenuItem.Text = "&Hide selected Node(s)";
 			this.hideNodesToolStripMenuItem.Click += new System.EventHandler(this.hideNodesToolStripMenuItem_Click);
 			// 
@@ -701,7 +713,7 @@ private void InitializeComponent()
             this.unhideNodesBelowToolStripMenuItem});
 			this.unhideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.unhideNodesToolStripMenuItem.Name = "unhideNodesToolStripMenuItem";
-			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.unhideNodesToolStripMenuItem.Text = "&Unhide...";
 			// 
 			// unhideChildNodesToolStripMenuItem
@@ -731,26 +743,26 @@ private void InitializeComponent()
 			// toolStripSeparator18
 			// 
 			this.toolStripSeparator18.Name = "toolStripSeparator18";
-			this.toolStripSeparator18.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator18.Size = new System.Drawing.Size(292, 6);
 			// 
 			// copyAddressToolStripMenuItem
 			// 
 			this.copyAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyAddressToolStripMenuItem.Name = "copyAddressToolStripMenuItem";
-			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.copyAddressToolStripMenuItem.Text = "Cop&y Address";
 			this.copyAddressToolStripMenuItem.Click += new System.EventHandler(this.copyAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator11
 			// 
 			this.toolStripSeparator11.Name = "toolStripSeparator11";
-			this.toolStripSeparator11.Size = new System.Drawing.Size(266, 6);
+			this.toolStripSeparator11.Size = new System.Drawing.Size(292, 6);
 			// 
 			// showCodeOfClassToolStripMenuItem
 			// 
 			this.showCodeOfClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Code_Cpp;
 			this.showCodeOfClassToolStripMenuItem.Name = "showCodeOfClassToolStripMenuItem";
-			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.showCodeOfClassToolStripMenuItem.Text = "Show C&++ Code of Class";
 			this.showCodeOfClassToolStripMenuItem.Click += new System.EventHandler(this.showCodeOfClassToolStripMenuItem_Click);
 			// 
@@ -758,7 +770,7 @@ private void InitializeComponent()
 			// 
 			this.shrinkClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Chart_Delete;
 			this.shrinkClassToolStripMenuItem.Name = "shrinkClassToolStripMenuItem";
-			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
 			this.shrinkClassToolStripMenuItem.Text = "Shri&nk Class";
 			this.shrinkClassToolStripMenuItem.Click += new System.EventHandler(this.shrinkClassToolStripMenuItem_Click);
 			// 
@@ -1543,6 +1555,7 @@ private void InitializeComponent()
 		private System.Windows.Forms.ToolStripMenuItem showEnumsToolStripMenuItem;
 		private System.Windows.Forms.ToolStripSeparator toolStripSeparator23;
 		private System.Windows.Forms.ToolStripMenuItem isLittleEndianToolStripMenuItem;
+		private System.Windows.Forms.ToolStripMenuItem autoNameClassToolStripMenuItem;
 	}
 }
 
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index e771a10d..435d7a87 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -835,6 +835,7 @@ private void memoryViewControl_SelectionChanged(object sender, EventArgs e)
 
 			addBytesToolStripDropDownButton.Enabled = parentContainer != null || isContainerNode;
 			insertBytesToolStripDropDownButton.Enabled = selectedNodes.Count == 1 && parentContainer != null && !isContainerNode;
+			autoNameClassToolStripMenuItem.Enabled = nodeIsClass;
 
 			var enabled = selectedNodes.Count > 0 && !nodeIsClass;
 			toolStrip.Items.OfType<TypeToolStripButton>().ForEach(b => b.Enabled = enabled);
@@ -1027,7 +1028,7 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 		{
 			var process = Program.RemoteProcess;
 
-			var classNode = CurrentClassNode;
+			var classNode = (args.Node as ClassNode) ?? CurrentClassNode;
 			if (classNode != null)
 			{
 				memoryViewBuffer.Size = classNode.MemorySize;
@@ -1051,5 +1052,17 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 				args.BaseAddress = address;
 			}
 		}
+
+
+		private void autoNameClassToolStripMenuItem_Click(object sender, EventArgs e)
+		{
+			var selectedNodes = memoryViewControl.GetSelectedNodes();
+			var node = selectedNodes.FirstOrDefault()?.Node;
+			if (node == null || !(node is ClassNode))
+			{
+				return;
+			}
+			memoryViewControl.AutoNameCurrentClassFromRTTI(node as ClassNode);
+		}
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseContainerNode.cs b/ReClass.NET/Nodes/BaseContainerNode.cs
index 6926111f..aa106dd0 100644
--- a/ReClass.NET/Nodes/BaseContainerNode.cs
+++ b/ReClass.NET/Nodes/BaseContainerNode.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics.Contracts;
 
@@ -183,8 +183,8 @@ public void ReplaceChildNode(BaseNode oldNode, BaseNode newNode, ref List<BaseNo
 			}
 
 			newNode.CopyFromNode(oldNode);
-
 			newNode.ParentNode = this;
+			newNode.PerformPostInitWork();
 
 			nodes[index] = newNode;
 
diff --git a/ReClass.NET/Nodes/BaseHexCommentNode.cs b/ReClass.NET/Nodes/BaseHexCommentNode.cs
index f2a4053f..da9f180e 100644
--- a/ReClass.NET/Nodes/BaseHexCommentNode.cs
+++ b/ReClass.NET/Nodes/BaseHexCommentNode.cs
@@ -44,7 +44,7 @@ protected int AddComment(DrawContext view, int x, int y, float fvalue, IntPtr iv
 
 					if (view.Settings.ShowCommentRtti)
 					{
-						var rtti = view.Process.ReadRemoteRuntimeTypeInformation(ivalue);
+						var rtti = GetAssociatedRemoteRuntimeTypeInformation(view, ivalue);
 						if (!string.IsNullOrEmpty(rtti))
 						{
 							x = AddText(view, x, y, view.Settings.OffsetColor, HotSpot.ReadOnlyId, rtti) + view.Font.Width;
@@ -110,5 +110,11 @@ protected int AddComment(DrawContext view, int x, int y, float fvalue, IntPtr iv
 
 			return x;
 		}
+
+
+		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context, IntPtr ivalue)
+		{
+			return context.Process.ReadRemoteRuntimeTypeInformation(ivalue);
+		}
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index adef39e5..43a0bd97 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -39,8 +39,8 @@ public abstract class BaseNode
 		/// <summary>Gets or sets the parent node.</summary>
 		public BaseNode ParentNode { get; internal set; }
 
-		/// <summary>Gets a value indicating whether this node is wrapped into an other node.</summary>
-		public bool IsWrapped => ParentNode is BaseWrapperNode;
+		/// <summary>Gets a value indicating whether this node is wrapped into an other node. We see classnodes never as wrapped.</summary>
+		public bool IsWrapped => (ParentNode is BaseWrapperNode && !(this is ClassNode));
 
 		/// <summary>Gets or sets a value indicating whether this node is hidden.</summary>
 		public bool IsHidden { get; set; }
@@ -236,6 +236,15 @@ public virtual void ClearSelection()
 		/// <returns>The calculated height.</returns>
 		public abstract int CalculateDrawnHeight(DrawContext context);
 
+		/// <summary>
+		/// Called when this node has been created, initialized and the parent node has been assigned. For some nodes
+		/// Additional work has to be performed, this work can be done in a derived method of this method.
+		/// </summary>
+		public virtual void PerformPostInitWork()
+		{
+			// nop
+		}
+
 		/// <summary>Updates the node from the given <paramref name="spot"/>. Sets the <see cref="Name"/> and <see cref="Comment"/> of the node.</summary>
 		/// <param name="spot">The spot.</param>
 		public virtual void Update(HotSpot spot)
diff --git a/ReClass.NET/Nodes/ClassNode.cs b/ReClass.NET/Nodes/ClassNode.cs
index 9b144061..92aa6691 100644
--- a/ReClass.NET/Nodes/ClassNode.cs
+++ b/ReClass.NET/Nodes/ClassNode.cs
@@ -52,6 +52,46 @@ public static ClassNode Create()
 			return new ClassNode(true);
 		}
 
+		
+		public void AutoNameFromRTTI(DrawContext context)
+		{
+			// first node should be a VTable node or a hex64/32 node
+			if (Nodes.Count <= 0)
+			{
+				return;
+			}
+
+			var rttiInfoFromFirstNode = string.Empty;
+			var firstNode = Nodes[0];
+			if (firstNode is VirtualMethodTableNode vtableNode)
+			{
+				rttiInfoFromFirstNode = vtableNode.GetAssociatedRemoteRuntimeTypeInformation(context);
+			}
+			else
+			{
+				if (firstNode is BaseHexCommentNode baseHexCommentNode)
+				{
+					// ask it as if it might point to a vtable
+					var value = context.Memory.ReadFromBuffer(Offset);
+					rttiInfoFromFirstNode = baseHexCommentNode.GetAssociatedRemoteRuntimeTypeInformation(context, value.IntPtr);
+					if (!string.IsNullOrEmpty(rttiInfoFromFirstNode))
+					{
+						// convert first node to vtable node
+#warning IMPLEMENT: CONVERT NODE TO VTABLE NODE
+					}
+				}
+			}
+
+			if (string.IsNullOrEmpty(rttiInfoFromFirstNode))
+			{
+				return;
+			}
+
+			var fragments = rttiInfoFromFirstNode.Split(':');
+			this.Name = fragments[0];
+		}
+		
+
 		public override void GetUserInterfaceInfo(out string name, out Image icon)
 		{
 			throw new InvalidOperationException($"The '{nameof(ClassNode)}' node should not be accessible from the ui.");
diff --git a/ReClass.NET/Nodes/PointerNode.cs b/ReClass.NET/Nodes/PointerNode.cs
index 027b0d28..47431aca 100644
--- a/ReClass.NET/Nodes/PointerNode.cs
+++ b/ReClass.NET/Nodes/PointerNode.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Drawing;
+using ReClassNET.AddressParser;
 using ReClassNET.Controls;
 using ReClassNET.Memory;
 using ReClassNET.UI;
@@ -134,5 +135,40 @@ public override int CalculateDrawnHeight(DrawContext context)
 			}
 			return height;
 		}
+
+
+		public override void PerformPostInitWork()
+		{
+			base.PerformPostInitWork();
+
+			var parentClass = ParentNode as ClassNode;
+			if (parentClass == null)
+			{
+				return;
+			}
+
+			var process = Program.RemoteProcess;
+			IntPtr address;
+			try
+			{
+				address = process.ParseAddress(parentClass.AddressFormula);
+			}
+			catch (ParseException)
+			{
+				address = IntPtr.Zero;
+			}
+
+			var memoryBuffer = new MemoryBuffer() { Size = parentClass.MemorySize};
+			memoryBuffer.UpdateFrom(process, address);
+			var ptr = memoryBuffer.ReadIntPtr(Offset);
+
+			var classNode = ((ClassInstanceNode)InnerNode)?.InnerNode as ClassNode;
+			if (classNode == null)
+			{
+				return;
+			}
+
+			classNode.AddressFormula = ptr.ToString(Constants.AddressHexFormat);
+		}
 	}
 }
diff --git a/ReClass.NET/Nodes/VirtualMethodTableNode.cs b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
index 3f58c3e5..8136a268 100644
--- a/ReClass.NET/Nodes/VirtualMethodTableNode.cs
+++ b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
@@ -41,18 +41,28 @@ protected override int AddComment(DrawContext context, int x, int y)
 			
 			if (context.Settings.ShowCommentRtti)
 			{
-				var addressFirstVTableFunction = context.Memory.ReadFromBuffer(Offset).IntPtr;
-				var rtti = context.Process.ReadRemoteRuntimeTypeInformation(addressFirstVTableFunction);
+				var rtti = GetAssociatedRemoteRuntimeTypeInformation(context);
 				if (!string.IsNullOrEmpty(rtti))
 				{
 					x = AddText(context, x, y, context.Settings.OffsetColor, HotSpot.ReadOnlyId, rtti) + context.Font.Width;
 				}
 			}
-
 			return x;
 		}
 
 
+		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context)
+		{
+			var addressFirstVTableFunction = context.Memory.ReadFromBuffer(Offset).IntPtr;
+			if (addressFirstVTableFunction != IntPtr.Zero)
+			{
+				return context.Process.ReadRemoteRuntimeTypeInformation(addressFirstVTableFunction);
+			}
+
+			return string.Empty;
+		}
+
+
 		public override Size Draw(DrawContext context, int x, int y)
 		{
 			if (IsHidden && !IsWrapped)
diff --git a/ReClass.NET/Properties/Resources.Designer.cs b/ReClass.NET/Properties/Resources.Designer.cs
index 3d412074..3738ffbc 100644
--- a/ReClass.NET/Properties/Resources.Designer.cs
+++ b/ReClass.NET/Properties/Resources.Designer.cs
@@ -19,7 +19,7 @@ namespace ReClassNET.Properties {
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     internal class Resources {
@@ -190,6 +190,16 @@ internal static System.Drawing.Bitmap B16x16_Button_Array {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap B16x16_Button_AutoName {
+            get {
+                object obj = ResourceManager.GetObject("B16x16_Button_AutoName", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>
@@ -1371,7 +1381,7 @@ internal static System.Drawing.Bitmap B32x32_Plugin {
         }
         
         /// <summary>
-        ///   Looks up a localized string similar to 2020/10/17 09:45:04
+        ///   Looks up a localized string similar to 2023/07/03 12:55:32
         ///.
         /// </summary>
         internal static string BuildDate {
diff --git a/ReClass.NET/Properties/Resources.resx b/ReClass.NET/Properties/Resources.resx
index 48c2c826..3cee6c55 100644
--- a/ReClass.NET/Properties/Resources.resx
+++ b/ReClass.NET/Properties/Resources.resx
@@ -517,4 +517,7 @@
   <data name="B16x16_Button_NUInt" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Images\B16x16_Button_NUInt.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="B16x16_Button_AutoName" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Images\B16x16_Button_AutoName.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>
\ No newline at end of file
diff --git a/ReClass.NET/ReClass.NET.csproj b/ReClass.NET/ReClass.NET.csproj
index 0c990cc2..6422eb12 100644
--- a/ReClass.NET/ReClass.NET.csproj
+++ b/ReClass.NET/ReClass.NET.csproj
@@ -1023,6 +1023,9 @@
   <ItemGroup>
     <None Include="Resources\Images\B16x16_Button_NUInt.png" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Images\B16x16_Button_AutoName.png" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
     <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">powershell -Command "((Get-Date).ToUniversalTime()).ToString(\"yyyy\/MM\/dd HH:mm:ss\") | Out-File '$(ProjectDir)Resources\BuildDate.txt'"</PreBuildEvent>
diff --git a/ReClass.NET/Resources/Images/B16x16_Button_AutoName.png b/ReClass.NET/Resources/Images/B16x16_Button_AutoName.png
new file mode 100644
index 0000000000000000000000000000000000000000..bfdd7e644810d074917d6fb6695b76118945290e
GIT binary patch
literal 383
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Ea{HEjtmUzPnffIy#(?lOI#yL
zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+AuIM3VOOYhE&{2`t$$4J+sk{wF{WU
z0%{A|CpL002srrgh%hxUBpph#wvv`-;85s_1q$|TFmU*8-J@Up*T}54Y0jKE@(w%=
z42KLDWK%RwFaEH2(V_zq93qWvHb4y<7;iZJ`~Cg>|M?lOnr<eEpKE-%;DLj|+eeQM
z1q1{z6g4V4FiaF>tN!*TafU%+6T^g^@(K+z3R-Q>lnGR%CbV1?P!Iqb!!|*D!^8ah
z`~H>}75)1E@UOc;Z%<;9f++*z5vQKXj&*Kq+1J*!ZDwTZcwunj)ETy90S->S)^27N
z0q%`#KC|saS6etRY!t}0KJ)U#wq^zg2E#?q-JX;@c>K8e`UBnQZ3YZ10&&b8g|ZF}
aj10baJB3T{WX=GFAcLo?pUXO@geCxDU5-Hj

literal 0
HcmV?d00001

diff --git a/ReClass.NET/UI/HotSpot.cs b/ReClass.NET/UI/HotSpot.cs
index 3a0d4bc0..27b949d0 100644
--- a/ReClass.NET/UI/HotSpot.cs
+++ b/ReClass.NET/UI/HotSpot.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Drawing;
 using ReClassNET.Memory;
 using ReClassNET.Nodes;

From b61edca698a3c7111c2d328e289ea966340b81f4 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 20:36:54 +0200
Subject: [PATCH 06/15] Changed 'Auto-name' into 'Init from RTTI' and it now
 also inits the vtable pointer automatically.

---
 ReClass.NET/Controls/MemoryViewControl.cs |  4 +-
 ReClass.NET/Forms/MainForm.Designer.cs    | 72 +++++++++++------------
 ReClass.NET/Forms/MainForm.cs             |  6 +-
 ReClass.NET/Nodes/BaseNode.cs             |  9 ++-
 ReClass.NET/Nodes/ClassNode.cs            | 13 +++-
 5 files changed, 57 insertions(+), 47 deletions(-)

diff --git a/ReClass.NET/Controls/MemoryViewControl.cs b/ReClass.NET/Controls/MemoryViewControl.cs
index 1769f05a..58aafb91 100644
--- a/ReClass.NET/Controls/MemoryViewControl.cs
+++ b/ReClass.NET/Controls/MemoryViewControl.cs
@@ -706,7 +706,7 @@ public void Reset()
 		}
 
 
-		public void AutoNameCurrentClassFromRTTI(ClassNode classNode)
+		public void InitCurrentClassFromRTTI(ClassNode classNode)
 		{
 			var args = new DrawContextRequestEventArgs { Node = classNode };
 
@@ -721,7 +721,7 @@ public void AutoNameCurrentClassFromRTTI(ClassNode classNode)
 						   Address = args.BaseAddress,
 						   Level = 0,
 					   };
-			classNode.AutoNameFromRTTI(view);
+			classNode.InitFromRTTI(view);
 		}
 	}
 }
diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index cb15cbe5..5fd3c74e 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -77,7 +77,7 @@ private void InitializeComponent()
 			this.toolStripSeparator8 = new System.Windows.Forms.ToolStripSeparator();
 			this.createClassFromNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator13 = new System.Windows.Forms.ToolStripSeparator();
-			this.autoNameClassToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+			this.initClassToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.dissectNodesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator();
 			this.searchForEqualValuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -383,7 +383,7 @@ private void InitializeComponent()
             this.toolStripSeparator8,
             this.createClassFromNodesToolStripMenuItem,
             this.toolStripSeparator13,
-            this.autoNameClassToolStripMenuItem,
+            this.initClassToolStripMenuItem,
             this.dissectNodesToolStripMenuItem,
             this.toolStripSeparator9,
             this.searchForEqualValuesToolStripMenuItem,
@@ -404,14 +404,14 @@ private void InitializeComponent()
             this.showCodeOfClassToolStripMenuItem,
             this.shrinkClassToolStripMenuItem});
 			this.selectedNodeContextMenuStrip.Name = "selectedNodeContextMenuStrip";
-			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(296, 454);
+			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 454);
 			this.selectedNodeContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.selectedNodeContextMenuStrip_Opening);
 			// 
 			// changeTypeToolStripMenuItem
 			// 
 			this.changeTypeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Exchange_Button;
 			this.changeTypeToolStripMenuItem.Name = "changeTypeToolStripMenuItem";
-			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.changeTypeToolStripMenuItem.Text = "&Change Type";
 			// 
 			// addBytesToolStripMenuItem
@@ -427,7 +427,7 @@ private void InitializeComponent()
             this.toolStripMenuItem1});
 			this.addBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Add_Bytes_X;
 			this.addBytesToolStripMenuItem.Name = "addBytesToolStripMenuItem";
-			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.addBytesToolStripMenuItem.Text = "&Add Bytes";
 			// 
 			// integerToolStripMenuItem1
@@ -514,7 +514,7 @@ private void InitializeComponent()
             this.toolStripMenuItem2});
 			this.insertBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Insert_Bytes_X;
 			this.insertBytesToolStripMenuItem.Name = "insertBytesToolStripMenuItem";
-			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.insertBytesToolStripMenuItem.Text = "&Insert Bytes";
 			// 
 			// integerToolStripMenuItem8
@@ -591,62 +591,62 @@ private void InitializeComponent()
 			// toolStripSeparator8
 			// 
 			this.toolStripSeparator8.Name = "toolStripSeparator8";
-			this.toolStripSeparator8.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator8.Size = new System.Drawing.Size(266, 6);
 			// 
 			// createClassFromNodesToolStripMenuItem
 			// 
 			this.createClassFromNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Class_Add;
 			this.createClassFromNodesToolStripMenuItem.Name = "createClassFromNodesToolStripMenuItem";
-			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.createClassFromNodesToolStripMenuItem.Text = "C&reate Class from Nodes";
 			this.createClassFromNodesToolStripMenuItem.Click += new System.EventHandler(this.createClassFromNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator13
 			// 
 			this.toolStripSeparator13.Name = "toolStripSeparator13";
-			this.toolStripSeparator13.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator13.Size = new System.Drawing.Size(266, 6);
 			// 
-			// autoNameClassToolStripMenuItem
+			// initClassToolStripMenuItem
 			// 
-			this.autoNameClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
-			this.autoNameClassToolStripMenuItem.Name = "autoNameClassToolStripMenuItem";
-			this.autoNameClassToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
+			this.initClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
+			this.initClassToolStripMenuItem.Name = "initClassToolStripMenuItem";
+			this.initClassToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
             | System.Windows.Forms.Keys.N)));
-			this.autoNameClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
-			this.autoNameClassToolStripMenuItem.Text = "Auto-Name Class from RTTI";
-			this.autoNameClassToolStripMenuItem.Click += new System.EventHandler(this.autoNameClassToolStripMenuItem_Click);
+			this.initClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
+			this.initClassToolStripMenuItem.Text = "Init Class from RTTI";
+			this.initClassToolStripMenuItem.Click += new System.EventHandler(this.initClassToolStripMenuItem_Click);
 			// 
 			// dissectNodesToolStripMenuItem
 			// 
 			this.dissectNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Camera;
 			this.dissectNodesToolStripMenuItem.Name = "dissectNodesToolStripMenuItem";
-			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.dissectNodesToolStripMenuItem.Text = "&Dissect Node(s)";
 			this.dissectNodesToolStripMenuItem.Click += new System.EventHandler(this.dissectNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator9
 			// 
 			this.toolStripSeparator9.Name = "toolStripSeparator9";
-			this.toolStripSeparator9.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator9.Size = new System.Drawing.Size(266, 6);
 			// 
 			// searchForEqualValuesToolStripMenuItem
 			// 
 			this.searchForEqualValuesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.searchForEqualValuesToolStripMenuItem.Name = "searchForEqualValuesToolStripMenuItem";
-			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.searchForEqualValuesToolStripMenuItem.Text = "&Search for equal values...";
 			this.searchForEqualValuesToolStripMenuItem.Click += new System.EventHandler(this.searchForEqualValuesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator15
 			// 
 			this.toolStripSeparator15.Name = "toolStripSeparator15";
-			this.toolStripSeparator15.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator15.Size = new System.Drawing.Size(266, 6);
 			// 
 			// findOutWhatAccessesThisAddressToolStripMenuItem
 			// 
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Access;
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Name = "findOutWhatAccessesThisAddressToolStripMenuItem";
-			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "&Find out what accesses this address...";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatAccessesThisAddressToolStripMenuItem_Click);
 			// 
@@ -654,20 +654,20 @@ private void InitializeComponent()
 			// 
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Write;
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Name = "findOutWhatWritesToThisAddressToolStripMenuItem";
-			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what &writes to this address...";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatWritesToThisAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator14
 			// 
 			this.toolStripSeparator14.Name = "toolStripSeparator14";
-			this.toolStripSeparator14.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator14.Size = new System.Drawing.Size(266, 6);
 			// 
 			// copyNodeToolStripMenuItem
 			// 
 			this.copyNodeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyNodeToolStripMenuItem.Name = "copyNodeToolStripMenuItem";
-			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.copyNodeToolStripMenuItem.Text = "C&opy Node(s)";
 			this.copyNodeToolStripMenuItem.Click += new System.EventHandler(this.copyNodeToolStripMenuItem_Click);
 			// 
@@ -675,33 +675,33 @@ private void InitializeComponent()
 			// 
 			this.pasteNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Paste;
 			this.pasteNodesToolStripMenuItem.Name = "pasteNodesToolStripMenuItem";
-			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.pasteNodesToolStripMenuItem.Text = "&Paste Node(s)";
 			this.pasteNodesToolStripMenuItem.Click += new System.EventHandler(this.pasteNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator10
 			// 
 			this.toolStripSeparator10.Name = "toolStripSeparator10";
-			this.toolStripSeparator10.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator10.Size = new System.Drawing.Size(266, 6);
 			// 
 			// removeToolStripMenuItem
 			// 
 			this.removeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Delete;
 			this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
-			this.removeToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.removeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.removeToolStripMenuItem.Text = "&Remove Node(s)";
 			this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator12
 			// 
 			this.toolStripSeparator12.Name = "toolStripSeparator12";
-			this.toolStripSeparator12.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator12.Size = new System.Drawing.Size(266, 6);
 			// 
 			// hideNodesToolStripMenuItem
 			// 
 			this.hideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.hideNodesToolStripMenuItem.Name = "hideNodesToolStripMenuItem";
-			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.hideNodesToolStripMenuItem.Text = "&Hide selected Node(s)";
 			this.hideNodesToolStripMenuItem.Click += new System.EventHandler(this.hideNodesToolStripMenuItem_Click);
 			// 
@@ -713,7 +713,7 @@ private void InitializeComponent()
             this.unhideNodesBelowToolStripMenuItem});
 			this.unhideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.unhideNodesToolStripMenuItem.Name = "unhideNodesToolStripMenuItem";
-			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.unhideNodesToolStripMenuItem.Text = "&Unhide...";
 			// 
 			// unhideChildNodesToolStripMenuItem
@@ -743,26 +743,26 @@ private void InitializeComponent()
 			// toolStripSeparator18
 			// 
 			this.toolStripSeparator18.Name = "toolStripSeparator18";
-			this.toolStripSeparator18.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator18.Size = new System.Drawing.Size(266, 6);
 			// 
 			// copyAddressToolStripMenuItem
 			// 
 			this.copyAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyAddressToolStripMenuItem.Name = "copyAddressToolStripMenuItem";
-			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.copyAddressToolStripMenuItem.Text = "Cop&y Address";
 			this.copyAddressToolStripMenuItem.Click += new System.EventHandler(this.copyAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator11
 			// 
 			this.toolStripSeparator11.Name = "toolStripSeparator11";
-			this.toolStripSeparator11.Size = new System.Drawing.Size(292, 6);
+			this.toolStripSeparator11.Size = new System.Drawing.Size(266, 6);
 			// 
 			// showCodeOfClassToolStripMenuItem
 			// 
 			this.showCodeOfClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Code_Cpp;
 			this.showCodeOfClassToolStripMenuItem.Name = "showCodeOfClassToolStripMenuItem";
-			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.showCodeOfClassToolStripMenuItem.Text = "Show C&++ Code of Class";
 			this.showCodeOfClassToolStripMenuItem.Click += new System.EventHandler(this.showCodeOfClassToolStripMenuItem_Click);
 			// 
@@ -770,7 +770,7 @@ private void InitializeComponent()
 			// 
 			this.shrinkClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Chart_Delete;
 			this.shrinkClassToolStripMenuItem.Name = "shrinkClassToolStripMenuItem";
-			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(295, 22);
+			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
 			this.shrinkClassToolStripMenuItem.Text = "Shri&nk Class";
 			this.shrinkClassToolStripMenuItem.Click += new System.EventHandler(this.shrinkClassToolStripMenuItem_Click);
 			// 
@@ -1555,7 +1555,7 @@ private void InitializeComponent()
 		private System.Windows.Forms.ToolStripMenuItem showEnumsToolStripMenuItem;
 		private System.Windows.Forms.ToolStripSeparator toolStripSeparator23;
 		private System.Windows.Forms.ToolStripMenuItem isLittleEndianToolStripMenuItem;
-		private System.Windows.Forms.ToolStripMenuItem autoNameClassToolStripMenuItem;
+		private System.Windows.Forms.ToolStripMenuItem initClassToolStripMenuItem;
 	}
 }
 
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index 435d7a87..0f02dbf2 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -835,7 +835,7 @@ private void memoryViewControl_SelectionChanged(object sender, EventArgs e)
 
 			addBytesToolStripDropDownButton.Enabled = parentContainer != null || isContainerNode;
 			insertBytesToolStripDropDownButton.Enabled = selectedNodes.Count == 1 && parentContainer != null && !isContainerNode;
-			autoNameClassToolStripMenuItem.Enabled = nodeIsClass;
+			initClassToolStripMenuItem.Enabled = nodeIsClass;
 
 			var enabled = selectedNodes.Count > 0 && !nodeIsClass;
 			toolStrip.Items.OfType<TypeToolStripButton>().ForEach(b => b.Enabled = enabled);
@@ -1054,7 +1054,7 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 		}
 
 
-		private void autoNameClassToolStripMenuItem_Click(object sender, EventArgs e)
+		private void initClassToolStripMenuItem_Click(object sender, EventArgs e)
 		{
 			var selectedNodes = memoryViewControl.GetSelectedNodes();
 			var node = selectedNodes.FirstOrDefault()?.Node;
@@ -1062,7 +1062,7 @@ private void autoNameClassToolStripMenuItem_Click(object sender, EventArgs e)
 			{
 				return;
 			}
-			memoryViewControl.AutoNameCurrentClassFromRTTI(node as ClassNode);
+			memoryViewControl.InitCurrentClassFromRTTI(node as ClassNode);
 		}
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index 43a0bd97..b5cefb00 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -39,8 +39,11 @@ public abstract class BaseNode
 		/// <summary>Gets or sets the parent node.</summary>
 		public BaseNode ParentNode { get; internal set; }
 
-		/// <summary>Gets a value indicating whether this node is wrapped into an other node. We see classnodes never as wrapped.</summary>
-		public bool IsWrapped => (ParentNode is BaseWrapperNode && !(this is ClassNode));
+		/// <summary>Gets a value indicating whether this node is wrapped into an other node. </summary>
+		public bool IsWrapped => (ParentNode is BaseWrapperNode);
+
+		/// <summary>All nodes that are wrapped can't be selected except classnodes because they have a context menu</summary>
+		public bool CanBeSelected => (!IsWrapped || (this is ClassNode));
 
 		/// <summary>Gets or sets a value indicating whether this node is hidden.</summary>
 		public bool IsHidden { get; set; }
@@ -376,7 +379,7 @@ protected void AddSelection(DrawContext context, int x, int y, int height)
 			Contract.Requires(context != null);
 			Contract.Requires(context.Graphics != null);
 
-			if (y > context.ClientArea.Bottom || y + height < 0 || IsWrapped)
+			if (y > context.ClientArea.Bottom || y + height < 0 || !CanBeSelected)
 			{
 				return;
 			}
diff --git a/ReClass.NET/Nodes/ClassNode.cs b/ReClass.NET/Nodes/ClassNode.cs
index 92aa6691..05aa9077 100644
--- a/ReClass.NET/Nodes/ClassNode.cs
+++ b/ReClass.NET/Nodes/ClassNode.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Diagnostics.Contracts;
 using System.Drawing;
 using System.Linq;
@@ -52,8 +53,12 @@ public static ClassNode Create()
 			return new ClassNode(true);
 		}
 
-		
-		public void AutoNameFromRTTI(DrawContext context)
+
+		/// <summary>
+		/// Initializes the class' name and vtable node from RTTI information, if it's not set already 
+		/// </summary>
+		/// <param name="context"></param>
+		public void InitFromRTTI(DrawContext context)
 		{
 			// first node should be a VTable node or a hex64/32 node
 			if (Nodes.Count <= 0)
@@ -77,7 +82,9 @@ public void AutoNameFromRTTI(DrawContext context)
 					if (!string.IsNullOrEmpty(rttiInfoFromFirstNode))
 					{
 						// convert first node to vtable node
-#warning IMPLEMENT: CONVERT NODE TO VTABLE NODE
+						var newVTableNode = BaseNode.CreateInstanceFromType(typeof(VirtualMethodTableNode));
+						var createdNodes = new List<BaseNode>();
+						this.ReplaceChildNode(firstNode, newVTableNode, ref createdNodes);
 					}
 				}
 			}

From 68b44d51caf501dfb4d8b98e6b383ed6bf0b10df Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Mon, 3 Jul 2023 20:42:12 +0200
Subject: [PATCH 07/15] Removed alt-key shortcuts from context menu as they
 can't be viewed anyway

---
 ReClass.NET/Forms/MainForm.Designer.cs | 32 +++++++++++++-------------
 1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index 5fd3c74e..adf1cf64 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -412,7 +412,7 @@ private void InitializeComponent()
 			this.changeTypeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Exchange_Button;
 			this.changeTypeToolStripMenuItem.Name = "changeTypeToolStripMenuItem";
 			this.changeTypeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.changeTypeToolStripMenuItem.Text = "&Change Type";
+			this.changeTypeToolStripMenuItem.Text = "Change Type";
 			// 
 			// addBytesToolStripMenuItem
 			// 
@@ -428,7 +428,7 @@ private void InitializeComponent()
 			this.addBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Add_Bytes_X;
 			this.addBytesToolStripMenuItem.Name = "addBytesToolStripMenuItem";
 			this.addBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.addBytesToolStripMenuItem.Text = "&Add Bytes";
+			this.addBytesToolStripMenuItem.Text = "Add Bytes";
 			// 
 			// integerToolStripMenuItem1
 			// 
@@ -515,7 +515,7 @@ private void InitializeComponent()
 			this.insertBytesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Insert_Bytes_X;
 			this.insertBytesToolStripMenuItem.Name = "insertBytesToolStripMenuItem";
 			this.insertBytesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.insertBytesToolStripMenuItem.Text = "&Insert Bytes";
+			this.insertBytesToolStripMenuItem.Text = "Insert Bytes";
 			// 
 			// integerToolStripMenuItem8
 			// 
@@ -598,7 +598,7 @@ private void InitializeComponent()
 			this.createClassFromNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Class_Add;
 			this.createClassFromNodesToolStripMenuItem.Name = "createClassFromNodesToolStripMenuItem";
 			this.createClassFromNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.createClassFromNodesToolStripMenuItem.Text = "C&reate Class from Nodes";
+			this.createClassFromNodesToolStripMenuItem.Text = "Create Class from Nodes";
 			this.createClassFromNodesToolStripMenuItem.Click += new System.EventHandler(this.createClassFromNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator13
@@ -621,7 +621,7 @@ private void InitializeComponent()
 			this.dissectNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Camera;
 			this.dissectNodesToolStripMenuItem.Name = "dissectNodesToolStripMenuItem";
 			this.dissectNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.dissectNodesToolStripMenuItem.Text = "&Dissect Node(s)";
+			this.dissectNodesToolStripMenuItem.Text = "Dissect Node(s)";
 			this.dissectNodesToolStripMenuItem.Click += new System.EventHandler(this.dissectNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator9
@@ -634,7 +634,7 @@ private void InitializeComponent()
 			this.searchForEqualValuesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.searchForEqualValuesToolStripMenuItem.Name = "searchForEqualValuesToolStripMenuItem";
 			this.searchForEqualValuesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.searchForEqualValuesToolStripMenuItem.Text = "&Search for equal values...";
+			this.searchForEqualValuesToolStripMenuItem.Text = "Search for equal values...";
 			this.searchForEqualValuesToolStripMenuItem.Click += new System.EventHandler(this.searchForEqualValuesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator15
@@ -647,7 +647,7 @@ private void InitializeComponent()
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Access;
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Name = "findOutWhatAccessesThisAddressToolStripMenuItem";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "&Find out what accesses this address...";
+			this.findOutWhatAccessesThisAddressToolStripMenuItem.Text = "Find out what accesses this address...";
 			this.findOutWhatAccessesThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatAccessesThisAddressToolStripMenuItem_Click);
 			// 
 			// findOutWhatWritesToThisAddressToolStripMenuItem
@@ -655,7 +655,7 @@ private void InitializeComponent()
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Find_Write;
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Name = "findOutWhatWritesToThisAddressToolStripMenuItem";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what &writes to this address...";
+			this.findOutWhatWritesToThisAddressToolStripMenuItem.Text = "Find out what writes to this address...";
 			this.findOutWhatWritesToThisAddressToolStripMenuItem.Click += new System.EventHandler(this.findOutWhatWritesToThisAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator14
@@ -668,7 +668,7 @@ private void InitializeComponent()
 			this.copyNodeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyNodeToolStripMenuItem.Name = "copyNodeToolStripMenuItem";
 			this.copyNodeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.copyNodeToolStripMenuItem.Text = "C&opy Node(s)";
+			this.copyNodeToolStripMenuItem.Text = "Copy Node(s)";
 			this.copyNodeToolStripMenuItem.Click += new System.EventHandler(this.copyNodeToolStripMenuItem_Click);
 			// 
 			// pasteNodesToolStripMenuItem
@@ -676,7 +676,7 @@ private void InitializeComponent()
 			this.pasteNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Paste;
 			this.pasteNodesToolStripMenuItem.Name = "pasteNodesToolStripMenuItem";
 			this.pasteNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.pasteNodesToolStripMenuItem.Text = "&Paste Node(s)";
+			this.pasteNodesToolStripMenuItem.Text = "Paste Node(s)";
 			this.pasteNodesToolStripMenuItem.Click += new System.EventHandler(this.pasteNodesToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator10
@@ -689,7 +689,7 @@ private void InitializeComponent()
 			this.removeToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_Delete;
 			this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
 			this.removeToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.removeToolStripMenuItem.Text = "&Remove Node(s)";
+			this.removeToolStripMenuItem.Text = "Remove Node(s)";
 			this.removeToolStripMenuItem.Click += new System.EventHandler(this.removeToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator12
@@ -702,7 +702,7 @@ private void InitializeComponent()
 			this.hideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.hideNodesToolStripMenuItem.Name = "hideNodesToolStripMenuItem";
 			this.hideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.hideNodesToolStripMenuItem.Text = "&Hide selected Node(s)";
+			this.hideNodesToolStripMenuItem.Text = "Hide selected Node(s)";
 			this.hideNodesToolStripMenuItem.Click += new System.EventHandler(this.hideNodesToolStripMenuItem_Click);
 			// 
 			// unhideNodesToolStripMenuItem
@@ -714,7 +714,7 @@ private void InitializeComponent()
 			this.unhideNodesToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Eye;
 			this.unhideNodesToolStripMenuItem.Name = "unhideNodesToolStripMenuItem";
 			this.unhideNodesToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.unhideNodesToolStripMenuItem.Text = "&Unhide...";
+			this.unhideNodesToolStripMenuItem.Text = "Unhide...";
 			// 
 			// unhideChildNodesToolStripMenuItem
 			// 
@@ -750,7 +750,7 @@ private void InitializeComponent()
 			this.copyAddressToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Copy;
 			this.copyAddressToolStripMenuItem.Name = "copyAddressToolStripMenuItem";
 			this.copyAddressToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.copyAddressToolStripMenuItem.Text = "Cop&y Address";
+			this.copyAddressToolStripMenuItem.Text = "Copy Address";
 			this.copyAddressToolStripMenuItem.Click += new System.EventHandler(this.copyAddressToolStripMenuItem_Click);
 			// 
 			// toolStripSeparator11
@@ -763,7 +763,7 @@ private void InitializeComponent()
 			this.showCodeOfClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Page_Code_Cpp;
 			this.showCodeOfClassToolStripMenuItem.Name = "showCodeOfClassToolStripMenuItem";
 			this.showCodeOfClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.showCodeOfClassToolStripMenuItem.Text = "Show C&++ Code of Class";
+			this.showCodeOfClassToolStripMenuItem.Text = "Show C++ Code of Class";
 			this.showCodeOfClassToolStripMenuItem.Click += new System.EventHandler(this.showCodeOfClassToolStripMenuItem_Click);
 			// 
 			// shrinkClassToolStripMenuItem
@@ -771,7 +771,7 @@ private void InitializeComponent()
 			this.shrinkClassToolStripMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Chart_Delete;
 			this.shrinkClassToolStripMenuItem.Name = "shrinkClassToolStripMenuItem";
 			this.shrinkClassToolStripMenuItem.Size = new System.Drawing.Size(269, 22);
-			this.shrinkClassToolStripMenuItem.Text = "Shri&nk Class";
+			this.shrinkClassToolStripMenuItem.Text = "Shrink Class";
 			this.shrinkClassToolStripMenuItem.Click += new System.EventHandler(this.shrinkClassToolStripMenuItem_Click);
 			// 
 			// toolStrip

From c831f9bd3ada8adc84072ed478ee9161263fe14b Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 10:10:40 +0200
Subject: [PATCH 08/15] Added a toolstrip button for Init class from RTTI so
 the shortcut works without opening the menu. Made the window a bit wider (was
 too small already) so all toolbar buttons are visible

---
 ReClass.NET/Forms/MainForm.Designer.cs | 28 +++++++++++++++++++-------
 ReClass.NET/Forms/MainForm.cs          |  1 +
 2 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index adf1cf64..c889df6c 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -107,6 +107,7 @@ private void InitializeComponent()
 			this.saveToolStripButton = new System.Windows.Forms.ToolStripButton();
 			this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator();
 			this.newClassToolStripButton = new System.Windows.Forms.ToolStripButton();
+			this.initClassFromRTTIToolStripBarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
 			this.addBytesToolStripDropDownButton = new System.Windows.Forms.ToolStripDropDownButton();
 			this.add4BytesToolStripMenuItem = new ReClassNET.Controls.IntegerToolStripMenuItem();
 			this.add8BytesToolStripMenuItem = new ReClassNET.Controls.IntegerToolStripMenuItem();
@@ -203,7 +204,7 @@ private void InitializeComponent()
 			// 
 			this.splitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control;
 			this.splitContainer.Panel2.Controls.Add(this.memoryViewControl);
-			this.splitContainer.Size = new System.Drawing.Size(1141, 524);
+			this.splitContainer.Size = new System.Drawing.Size(1313, 524);
 			this.splitContainer.SplitterDistance = 201;
 			this.splitContainer.TabIndex = 4;
 			// 
@@ -365,7 +366,7 @@ private void InitializeComponent()
 			this.memoryViewControl.Location = new System.Drawing.Point(0, 0);
 			this.memoryViewControl.Name = "memoryViewControl";
 			this.memoryViewControl.NodeContextMenuStrip = this.selectedNodeContextMenuStrip;
-			this.memoryViewControl.Size = new System.Drawing.Size(936, 524);
+			this.memoryViewControl.Size = new System.Drawing.Size(1108, 524);
 			this.memoryViewControl.TabIndex = 0;
 			this.memoryViewControl.DrawContextRequested += new ReClassNET.Controls.DrawContextRequestEventHandler(this.memoryViewControl_DrawContextRequested);
 			this.memoryViewControl.SelectionChanged += new System.EventHandler(this.memoryViewControl_SelectionChanged);
@@ -404,7 +405,7 @@ private void InitializeComponent()
             this.showCodeOfClassToolStripMenuItem,
             this.shrinkClassToolStripMenuItem});
 			this.selectedNodeContextMenuStrip.Name = "selectedNodeContextMenuStrip";
-			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 454);
+			this.selectedNodeContextMenuStrip.Size = new System.Drawing.Size(270, 432);
 			this.selectedNodeContextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.selectedNodeContextMenuStrip_Opening);
 			// 
 			// changeTypeToolStripMenuItem
@@ -783,12 +784,13 @@ private void InitializeComponent()
             this.saveToolStripButton,
             this.toolStripSeparator7,
             this.newClassToolStripButton,
+            this.initClassFromRTTIToolStripBarMenuItem,
             this.addBytesToolStripDropDownButton,
             this.insertBytesToolStripDropDownButton,
             this.nodeTypesToolStripSeparator});
 			this.toolStrip.Location = new System.Drawing.Point(0, 24);
 			this.toolStrip.Name = "toolStrip";
-			this.toolStrip.Size = new System.Drawing.Size(1141, 25);
+			this.toolStrip.Size = new System.Drawing.Size(1313, 25);
 			this.toolStrip.TabIndex = 3;
 			// 
 			// attachToProcessToolStripSplitButton
@@ -844,6 +846,17 @@ private void InitializeComponent()
 			this.newClassToolStripButton.ToolTipText = "Add a new class to this project";
 			this.newClassToolStripButton.Click += new System.EventHandler(this.newClassToolStripButton_Click);
 			// 
+			// initClassFromRTTIToolStripBarMenuItem
+			// 
+			this.initClassFromRTTIToolStripBarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
+			this.initClassFromRTTIToolStripBarMenuItem.Name = "initClassFromRTTIToolStripBarMenuItem";
+			this.initClassFromRTTIToolStripBarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
+            | System.Windows.Forms.Keys.N)));
+			this.initClassFromRTTIToolStripBarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.initClassFromRTTIToolStripBarMenuItem.ToolTipText = "Init selected class from RTTI info";
+			this.initClassFromRTTIToolStripBarMenuItem.Value = null;
+			this.initClassFromRTTIToolStripBarMenuItem.Click += new System.EventHandler(this.initClassToolStripMenuItem_Click);
+			// 
 			// addBytesToolStripDropDownButton
 			// 
 			this.addBytesToolStripDropDownButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
@@ -1035,7 +1048,7 @@ private void InitializeComponent()
             this.infoToolStripStatusLabel});
 			this.statusStrip.Location = new System.Drawing.Point(0, 573);
 			this.statusStrip.Name = "statusStrip";
-			this.statusStrip.Size = new System.Drawing.Size(1141, 22);
+			this.statusStrip.Size = new System.Drawing.Size(1313, 22);
 			this.statusStrip.TabIndex = 1;
 			// 
 			// processInfoToolStripStatusLabel
@@ -1060,7 +1073,7 @@ private void InitializeComponent()
             this.helpToolStripMenuItem});
 			this.mainMenuStrip.Location = new System.Drawing.Point(0, 0);
 			this.mainMenuStrip.Name = "mainMenuStrip";
-			this.mainMenuStrip.Size = new System.Drawing.Size(1141, 24);
+			this.mainMenuStrip.Size = new System.Drawing.Size(1313, 24);
 			this.mainMenuStrip.TabIndex = 2;
 			// 
 			// fileToolStripMenuItem
@@ -1384,7 +1397,7 @@ private void InitializeComponent()
 			this.AllowDrop = true;
 			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-			this.ClientSize = new System.Drawing.Size(1141, 595);
+			this.ClientSize = new System.Drawing.Size(1313, 595);
 			this.Controls.Add(this.splitContainer);
 			this.Controls.Add(this.toolStrip);
 			this.Controls.Add(this.statusStrip);
@@ -1556,6 +1569,7 @@ private void InitializeComponent()
 		private System.Windows.Forms.ToolStripSeparator toolStripSeparator23;
 		private System.Windows.Forms.ToolStripMenuItem isLittleEndianToolStripMenuItem;
 		private System.Windows.Forms.ToolStripMenuItem initClassToolStripMenuItem;
+		private TypeToolStripMenuItem initClassFromRTTIToolStripBarMenuItem;
 	}
 }
 
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index 0f02dbf2..0d968bfc 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -836,6 +836,7 @@ private void memoryViewControl_SelectionChanged(object sender, EventArgs e)
 			addBytesToolStripDropDownButton.Enabled = parentContainer != null || isContainerNode;
 			insertBytesToolStripDropDownButton.Enabled = selectedNodes.Count == 1 && parentContainer != null && !isContainerNode;
 			initClassToolStripMenuItem.Enabled = nodeIsClass;
+			initClassFromRTTIToolStripBarMenuItem.Enabled = nodeIsClass;
 
 			var enabled = selectedNodes.Count > 0 && !nodeIsClass;
 			toolStrip.Items.OfType<TypeToolStripButton>().ForEach(b => b.Enabled = enabled);

From 59310506e78e9ff1e4e4f0cc5698df04955b2b5e Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 10:19:08 +0200
Subject: [PATCH 09/15] Initial packages update

---
 ReClass.NET/ReClass.NET.csproj | 7 +++++++
 ReClass.NET/packages.config    | 5 +++++
 2 files changed, 12 insertions(+)
 create mode 100644 ReClass.NET/packages.config

diff --git a/ReClass.NET/ReClass.NET.csproj b/ReClass.NET/ReClass.NET.csproj
index 6422eb12..3a98a45a 100644
--- a/ReClass.NET/ReClass.NET.csproj
+++ b/ReClass.NET/ReClass.NET.csproj
@@ -122,6 +122,12 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\Dependencies\Microsoft.ExceptionMessageBox.dll</HintPath>
     </Reference>
+    <Reference Include="SD.Tools.Algorithmia, Version=1.4.0.0, Culture=neutral, PublicKeyToken=8ede9265bbb8e107, processorArchitecture=MSIL">
+      <HintPath>..\packages\SD.Tools.Algorithmia.1.4.0\lib\net452\SD.Tools.Algorithmia.dll</HintPath>
+    </Reference>
+    <Reference Include="SD.Tools.BCLExtensions, Version=1.2.2.0, Culture=neutral, PublicKeyToken=a3f87088dcb994e1, processorArchitecture=MSIL">
+      <HintPath>..\packages\SD.Tools.BCLExtensions.1.2.2\lib\net452\SD.Tools.BCLExtensions.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Design" />
@@ -608,6 +614,7 @@
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
     </EmbeddedResource>
     <Compile Include="Debugger\RemoteDebugger.Handler.cs" />
+    <None Include="packages.config" />
     <None Include="Properties\Settings.settings">
       <Generator>SettingsSingleFileGenerator</Generator>
       <LastGenOutput>Settings.Designer.cs</LastGenOutput>
diff --git a/ReClass.NET/packages.config b/ReClass.NET/packages.config
new file mode 100644
index 00000000..67c03fdf
--- /dev/null
+++ b/ReClass.NET/packages.config
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="SD.Tools.Algorithmia" version="1.4.0" targetFramework="net472" />
+  <package id="SD.Tools.BCLExtensions" version="1.2.2" targetFramework="net472" />
+</packages>
\ No newline at end of file

From dc5225e0cdf16611ffde03ef09c454c183db38a7 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 10:20:16 +0200
Subject: [PATCH 10/15] Marked Init class from RTTI toolbar button as 'Overflow
 as needed' so it gets removed when the window is too narrow

---
 ReClass.NET/Forms/MainForm.Designer.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index c889df6c..081e2c0d 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -848,8 +848,10 @@ private void InitializeComponent()
 			// 
 			// initClassFromRTTIToolStripBarMenuItem
 			// 
+			this.initClassFromRTTIToolStripBarMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image;
 			this.initClassFromRTTIToolStripBarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Button_AutoName;
 			this.initClassFromRTTIToolStripBarMenuItem.Name = "initClassFromRTTIToolStripBarMenuItem";
+			this.initClassFromRTTIToolStripBarMenuItem.Overflow = System.Windows.Forms.ToolStripItemOverflow.AsNeeded;
 			this.initClassFromRTTIToolStripBarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)(((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Shift) 
             | System.Windows.Forms.Keys.N)));
 			this.initClassFromRTTIToolStripBarMenuItem.Size = new System.Drawing.Size(28, 25);

From 35afcee8ea1666bfa3fa3af3bbfdf5973dba6902 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 10:36:40 +0200
Subject: [PATCH 11/15] Defined some node type toolbar buttons as 'As Needed'
 for overflow if the window is too narrow to make room for undo/redo buttons

---
 ReClass.NET/Forms/MainForm.Designer.cs | 12 ++++++------
 ReClass.NET/UI/NodeTypesBuilder.cs     |  5 +++++
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index 081e2c0d..b2448e7d 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -204,7 +204,7 @@ private void InitializeComponent()
 			// 
 			this.splitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control;
 			this.splitContainer.Panel2.Controls.Add(this.memoryViewControl);
-			this.splitContainer.Size = new System.Drawing.Size(1313, 524);
+			this.splitContainer.Size = new System.Drawing.Size(1103, 524);
 			this.splitContainer.SplitterDistance = 201;
 			this.splitContainer.TabIndex = 4;
 			// 
@@ -366,7 +366,7 @@ private void InitializeComponent()
 			this.memoryViewControl.Location = new System.Drawing.Point(0, 0);
 			this.memoryViewControl.Name = "memoryViewControl";
 			this.memoryViewControl.NodeContextMenuStrip = this.selectedNodeContextMenuStrip;
-			this.memoryViewControl.Size = new System.Drawing.Size(1108, 524);
+			this.memoryViewControl.Size = new System.Drawing.Size(898, 524);
 			this.memoryViewControl.TabIndex = 0;
 			this.memoryViewControl.DrawContextRequested += new ReClassNET.Controls.DrawContextRequestEventHandler(this.memoryViewControl_DrawContextRequested);
 			this.memoryViewControl.SelectionChanged += new System.EventHandler(this.memoryViewControl_SelectionChanged);
@@ -790,7 +790,7 @@ private void InitializeComponent()
             this.nodeTypesToolStripSeparator});
 			this.toolStrip.Location = new System.Drawing.Point(0, 24);
 			this.toolStrip.Name = "toolStrip";
-			this.toolStrip.Size = new System.Drawing.Size(1313, 25);
+			this.toolStrip.Size = new System.Drawing.Size(1103, 25);
 			this.toolStrip.TabIndex = 3;
 			// 
 			// attachToProcessToolStripSplitButton
@@ -1050,7 +1050,7 @@ private void InitializeComponent()
             this.infoToolStripStatusLabel});
 			this.statusStrip.Location = new System.Drawing.Point(0, 573);
 			this.statusStrip.Name = "statusStrip";
-			this.statusStrip.Size = new System.Drawing.Size(1313, 22);
+			this.statusStrip.Size = new System.Drawing.Size(1103, 22);
 			this.statusStrip.TabIndex = 1;
 			// 
 			// processInfoToolStripStatusLabel
@@ -1075,7 +1075,7 @@ private void InitializeComponent()
             this.helpToolStripMenuItem});
 			this.mainMenuStrip.Location = new System.Drawing.Point(0, 0);
 			this.mainMenuStrip.Name = "mainMenuStrip";
-			this.mainMenuStrip.Size = new System.Drawing.Size(1313, 24);
+			this.mainMenuStrip.Size = new System.Drawing.Size(1103, 24);
 			this.mainMenuStrip.TabIndex = 2;
 			// 
 			// fileToolStripMenuItem
@@ -1399,7 +1399,7 @@ private void InitializeComponent()
 			this.AllowDrop = true;
 			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-			this.ClientSize = new System.Drawing.Size(1313, 595);
+			this.ClientSize = new System.Drawing.Size(1103, 595);
 			this.Controls.Add(this.splitContainer);
 			this.Controls.Add(this.toolStrip);
 			this.Controls.Add(this.statusStrip);
diff --git a/ReClass.NET/UI/NodeTypesBuilder.cs b/ReClass.NET/UI/NodeTypesBuilder.cs
index b0badd25..79d4bfbe 100644
--- a/ReClass.NET/UI/NodeTypesBuilder.cs
+++ b/ReClass.NET/UI/NodeTypesBuilder.cs
@@ -14,6 +14,7 @@ internal static class NodeTypesBuilder
 	{
 		private static readonly List<Type[]> defaultNodeTypeGroupList = new List<Type[]>();
 		private static readonly Dictionary<Plugin, IReadOnlyList<Type>> pluginNodeTypes = new Dictionary<Plugin, IReadOnlyList<Type>>();
+		private static readonly HashSet<Type> nodeTypesWhichCanOverflowInToolbar;
 
 		static NodeTypesBuilder()
 		{
@@ -27,6 +28,9 @@ static NodeTypesBuilder()
 			defaultNodeTypeGroupList.Add(new[] { typeof(PointerNode), typeof(ArrayNode), typeof(UnionNode) });
 			defaultNodeTypeGroupList.Add(new[] { typeof(ClassInstanceNode) });
 			defaultNodeTypeGroupList.Add(new[] { typeof(VirtualMethodTableNode), typeof(FunctionNode), typeof(FunctionPtrNode) });
+
+			// define the node types which can overflow in the toolbar if the window is too narrow. Add types here which aren't used that much 
+			nodeTypesWhichCanOverflowInToolbar = new HashSet<Type> { typeof(NIntNode), typeof(NUIntNode), typeof(BitFieldNode), typeof(Utf16TextNode), typeof(Utf16TextPtrNode) } ;
 		}
 
 		public static void AddPluginNodeGroup(Plugin plugin, IReadOnlyList<Type> nodeTypes)
@@ -66,6 +70,7 @@ public static IEnumerable<ToolStripItem> CreateToolStripButtons(Action<Type> han
 					DisplayStyle = ToolStripItemDisplayStyle.Image,
 					Image = icon,
 					ShortcutKeys = shortcutKeys,
+					Overflow = nodeTypesWhichCanOverflowInToolbar.Contains(t) ? ToolStripItemOverflow.AsNeeded : ToolStripItemOverflow.Never,
 				};
 				item.Click += clickHandler;
 				return item;

From fb7b4d69ba5e3ca0427304fa592cc4d48279eebe Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 11:41:41 +0200
Subject: [PATCH 12/15] Initial undo/redo system in place. Class name is now
 undo/redo aware

---
 ReClass.NET/Constants.cs                | 11 +++++++-
 ReClass.NET/Forms/MainForm.Designer.cs  | 28 +++++++++++++++++++-
 ReClass.NET/Forms/MainForm.Functions.cs |  9 +++++++
 ReClass.NET/Forms/MainForm.cs           | 35 +++++++++++++++++++++++++
 ReClass.NET/Nodes/BaseNode.cs           | 23 +++++++++++++---
 ReClass.NET/Program.cs                  |  9 +++++++
 6 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/ReClass.NET/Constants.cs b/ReClass.NET/Constants.cs
index 4e54782a..bd918dbe 100644
--- a/ReClass.NET/Constants.cs
+++ b/ReClass.NET/Constants.cs
@@ -1,4 +1,4 @@
-namespace ReClassNET
+namespace ReClassNET
 {
 	public class Constants
 	{
@@ -39,5 +39,14 @@ public static class CommandLineOptions
 			public const string FileExtRegister = "registerfileext";
 			public const string FileExtUnregister = "unregisterfileext";
 		}
+
+		/// <summary>
+		/// Change type for commandified members in classes which is used to signal what change occurred exactly. As we don't use this feature of the commandified
+		/// class, this enum is defined to simply signal 'no specific change other than it changed' happened. 
+		/// </summary>
+		public enum GeneralPurposeChangeType
+		{
+			None
+		}
 	}
 }
diff --git a/ReClass.NET/Forms/MainForm.Designer.cs b/ReClass.NET/Forms/MainForm.Designer.cs
index b2448e7d..20b2c907 100644
--- a/ReClass.NET/Forms/MainForm.Designer.cs
+++ b/ReClass.NET/Forms/MainForm.Designer.cs
@@ -169,6 +169,8 @@ private void InitializeComponent()
 			this.generateCSharpCodeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
 			this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+			this.undoToolbarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
+			this.redoToolbarMenuItem = new ReClassNET.Controls.TypeToolStripMenuItem();
 			((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
 			this.splitContainer.Panel1.SuspendLayout();
 			this.splitContainer.Panel2.SuspendLayout();
@@ -787,7 +789,9 @@ private void InitializeComponent()
             this.initClassFromRTTIToolStripBarMenuItem,
             this.addBytesToolStripDropDownButton,
             this.insertBytesToolStripDropDownButton,
-            this.nodeTypesToolStripSeparator});
+            this.nodeTypesToolStripSeparator,
+            this.undoToolbarMenuItem,
+            this.redoToolbarMenuItem});
 			this.toolStrip.Location = new System.Drawing.Point(0, 24);
 			this.toolStrip.Name = "toolStrip";
 			this.toolStrip.Size = new System.Drawing.Size(1103, 25);
@@ -1394,6 +1398,26 @@ private void InitializeComponent()
 			this.aboutToolStripMenuItem.Text = "About...";
 			this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click);
 			// 
+			// undoToolbarMenuItem
+			// 
+			this.undoToolbarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Undo;
+			this.undoToolbarMenuItem.Name = "undoToolbarMenuItem";
+			this.undoToolbarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z)));
+			this.undoToolbarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.undoToolbarMenuItem.ToolTipText = "Undo the latest change";
+			this.undoToolbarMenuItem.Value = null;
+			this.undoToolbarMenuItem.Click += new System.EventHandler(this.undoToolbarMenuItem_Click);
+			// 
+			// redoToolbarMenuItem
+			// 
+			this.redoToolbarMenuItem.Image = global::ReClassNET.Properties.Resources.B16x16_Redo;
+			this.redoToolbarMenuItem.Name = "redoToolbarMenuItem";
+			this.redoToolbarMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y)));
+			this.redoToolbarMenuItem.Size = new System.Drawing.Size(28, 25);
+			this.redoToolbarMenuItem.ToolTipText = "Redo the latest undone change";
+			this.redoToolbarMenuItem.Value = null;
+			this.redoToolbarMenuItem.Click += new System.EventHandler(this.redoToolbarMenuItem_Click);
+			// 
 			// MainForm
 			// 
 			this.AllowDrop = true;
@@ -1572,6 +1596,8 @@ private void InitializeComponent()
 		private System.Windows.Forms.ToolStripMenuItem isLittleEndianToolStripMenuItem;
 		private System.Windows.Forms.ToolStripMenuItem initClassToolStripMenuItem;
 		private TypeToolStripMenuItem initClassFromRTTIToolStripBarMenuItem;
+		private TypeToolStripMenuItem undoToolbarMenuItem;
+		private TypeToolStripMenuItem redoToolbarMenuItem;
 	}
 }
 
diff --git a/ReClass.NET/Forms/MainForm.Functions.cs b/ReClass.NET/Forms/MainForm.Functions.cs
index 84f1b53a..bc668e01 100644
--- a/ReClass.NET/Forms/MainForm.Functions.cs
+++ b/ReClass.NET/Forms/MainForm.Functions.cs
@@ -16,6 +16,7 @@
 using ReClassNET.Nodes;
 using ReClassNET.Project;
 using ReClassNET.UI;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET.Forms
 {
@@ -213,6 +214,10 @@ public void LoadProjectFromPath(string path)
 		{
 			Contract.Requires(path != null);
 
+			CommandQueueManagerSingleton.GetInstance().ResetActiveCommandQueue();
+			CommandQueueManagerSingleton.GetInstance().BeginNonUndoablePeriod();		// we don't want to trigger undo/redo activity while loading
+			CommandQueueManagerSingleton.GetInstance().RaiseEvents = false;
+
 			var project = new ReClassNetProject();
 
 			LoadProjectFromPath(path, ref project);
@@ -224,6 +229,10 @@ public void LoadProjectFromPath(string path)
 			}
 
 			SetProject(project);
+
+			// Done loading, resume undo/redo activity
+			CommandQueueManagerSingleton.GetInstance().RaiseEvents = true;
+			CommandQueueManagerSingleton.GetInstance().EndNonUndoablePeriod();
 		}
 
 		/// <summary>Loads the file into the given project.</summary>
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index 0d968bfc..c694ca31 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -22,6 +22,7 @@
 using ReClassNET.UI;
 using ReClassNET.Util;
 using ReClassNET.Util.Conversion;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET.Forms
 {
@@ -95,8 +96,11 @@ public MainForm()
 			};
 
 			pluginManager = new PluginManager(new DefaultPluginHost(this, Program.RemoteProcess, Program.Logger));
+
+			CommandQueueManagerSingleton.GetInstance().CommandQueueActionPerformed += OnCommandQueueActionPerformed;
 		}
 
+
 		protected override void OnLoad(EventArgs e)
 		{
 			base.OnLoad(e);
@@ -135,6 +139,8 @@ protected override void OnLoad(EventArgs e)
 			{
 				AttachToProcess(Program.CommandLineArgs[Constants.CommandLineOptions.AttachTo]);
 			}
+
+			SetStateOfUndoRedoButtons();
 		}
 
 		protected override void OnFormClosed(FormClosedEventArgs e)
@@ -1063,7 +1069,36 @@ private void initClassToolStripMenuItem_Click(object sender, EventArgs e)
 			{
 				return;
 			}
+
+			var cmd = new UndoablePeriodCommand("InitClassFromRTTI");
+			CommandQueueManagerSingleton.GetInstance().BeginUndoablePeriod(cmd);
 			memoryViewControl.InitCurrentClassFromRTTI(node as ClassNode);
+			CommandQueueManagerSingleton.GetInstance().EndUndoablePeriod(cmd);
+		}
+
+
+		private void SetStateOfUndoRedoButtons()
+		{
+			undoToolbarMenuItem.Enabled = CommandQueueManagerSingleton.GetInstance().CanUndo(Program.CommandQueueID);
+			redoToolbarMenuItem.Enabled = CommandQueueManagerSingleton.GetInstance().CanDo(Program.CommandQueueID);
+		}
+
+
+		private void OnCommandQueueActionPerformed(object sender, CommandQueueActionPerformedEventArgs e)
+		{
+			SetStateOfUndoRedoButtons();
+		}
+
+
+		private void undoToolbarMenuItem_Click(object sender, EventArgs e)
+		{
+			CommandQueueManagerSingleton.GetInstance().UndoLastCommand();
+		}
+
+
+		private void redoToolbarMenuItem_Click(object sender, EventArgs e)
+		{
+			CommandQueueManagerSingleton.GetInstance().RedoLastCommand();
 		}
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index b5cefb00..ff18e9f1 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -7,6 +7,8 @@
 using ReClassNET.Extensions;
 using ReClassNET.UI;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Nodes
 {
@@ -24,14 +26,26 @@ public abstract class BaseNode
 
 		private static int nodeIndex = 0;
 
-		private string name = string.Empty;
+		//private string name = string.Empty;
+		private CommandifiedMember<string, Constants.GeneralPurposeChangeType> name;
 		private string comment = string.Empty;
 
 		/// <summary>Gets or sets the offset of the node.</summary>
 		public int Offset { get; set; }
 
 		/// <summary>Gets or sets the name of the node. If a new name was set the property changed event gets fired.</summary>
-		public virtual string Name { get => name; set { if (value != null && name != value) { name = value; NameChanged?.Invoke(this); } } }
+		public virtual string Name
+		{
+			get => name.MemberValue;
+			set
+			{
+				if (value == null)
+				{
+					return;
+				}
+				name.MemberValue = value;
+			}
+		}
 
 		/// <summary>Gets or sets the comment of the node.</summary>
 		public string Comment { get => comment; set { if (value != null && comment != value) { comment = value; CommentChanged?.Invoke(this); } } }
@@ -100,12 +114,15 @@ protected BaseNode()
 			Contract.Ensures(name != null);
 			Contract.Ensures(comment != null);
 
-			Name = $"N{nodeIndex++:X08}";
+			name = new CommandifiedMember<string, Constants.GeneralPurposeChangeType>("Name", Constants.GeneralPurposeChangeType.None, $"N{nodeIndex++:X08}");
+			name.ValueChanged += Name_ValueChanged;
 			Comment = string.Empty;
 
 			LevelsOpen[0] = true;
 		}
 
+		private void Name_ValueChanged(object sender, MemberChangedEventArgs<Constants.GeneralPurposeChangeType, string> e) => NameChanged?.Invoke(this);
+
 		public abstract void GetUserInterfaceInfo(out string name, out Image icon);
 
 		public virtual bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
diff --git a/ReClass.NET/Program.cs b/ReClass.NET/Program.cs
index f28cb0bd..4a1dd5d4 100644
--- a/ReClass.NET/Program.cs
+++ b/ReClass.NET/Program.cs
@@ -11,6 +11,7 @@
 using ReClassNET.Native;
 using ReClassNET.UI;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.Commands;
 
 namespace ReClassNET
 {
@@ -34,10 +35,13 @@ public static class Program
 
 		public static FontEx MonoSpaceFont { get; private set; }
 
+		public static Guid CommandQueueID { get; private set; }
+
 		[STAThread]
 		static void Main(string[] args)
 		{
 			DesignMode = false; // The designer doesn't call Main()
+			CommandQueueID = Guid.NewGuid();
 
 			CommandLineArgs = new CommandLineArgs(args);
 
@@ -63,6 +67,11 @@ static void Main(string[] args)
 			Application.EnableVisualStyles();
 			Application.SetCompatibleTextRenderingDefault(false);
 
+			// switch is set to false, so Do actions during Undo actions are ignored.
+			CommandQueueManager.ThrowExceptionOnDoDuringUndo = false;
+			// activate our command queue stack. We're only changing things from the main thread so we don't need multiple stacks.
+			CommandQueueManagerSingleton.GetInstance().ActivateCommandQueueStack(CommandQueueID);
+
 			CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
 
 			Settings = SettingsSerializer.Load();

From aa8a85788a1410ab7ef5dfdf529fa596552b2a43 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 11:53:02 +0200
Subject: [PATCH 13/15] Removed 2nd empty lines when introduced, added 32bit
 version of ReadFromBuffer to MemoryBuffer, have refactored Hex32Node to use
 this method instead, have removed unnecessary braces and brackets.

---
 ReClass.NET/Controls/MemoryViewControl.cs   |  3 +--
 ReClass.NET/Forms/MainForm.cs               |  3 +--
 ReClass.NET/Memory/MemoryBuffer.cs          | 11 ++++++---
 ReClass.NET/Nodes/BaseHexCommentNode.cs     |  1 -
 ReClass.NET/Nodes/BaseNode.cs               |  4 ++--
 ReClass.NET/Nodes/ClassNode.cs              | 25 +++++++++------------
 ReClass.NET/Nodes/Hex32Node.cs              | 11 +++------
 ReClass.NET/Nodes/Hex64Node.cs              |  6 ++---
 ReClass.NET/Nodes/PointerNode.cs            |  3 +--
 ReClass.NET/Nodes/VirtualMethodTableNode.cs | 11 ++++-----
 ReClass.NET/Settings.cs                     |  6 +----
 11 files changed, 34 insertions(+), 50 deletions(-)

diff --git a/ReClass.NET/Controls/MemoryViewControl.cs b/ReClass.NET/Controls/MemoryViewControl.cs
index 58aafb91..d323903b 100644
--- a/ReClass.NET/Controls/MemoryViewControl.cs
+++ b/ReClass.NET/Controls/MemoryViewControl.cs
@@ -704,8 +704,7 @@ public void Reset()
 
 			VerticalScroll.Value = VerticalScroll.Minimum;
 		}
-
-
+		
 		public void InitCurrentClassFromRTTI(ClassNode classNode)
 		{
 			var args = new DrawContextRequestEventArgs { Node = classNode };
diff --git a/ReClass.NET/Forms/MainForm.cs b/ReClass.NET/Forms/MainForm.cs
index 0d968bfc..11c0d42d 100644
--- a/ReClass.NET/Forms/MainForm.cs
+++ b/ReClass.NET/Forms/MainForm.cs
@@ -1053,8 +1053,7 @@ private void memoryViewControl_DrawContextRequested(object sender, DrawContextRe
 				args.BaseAddress = address;
 			}
 		}
-
-
+		
 		private void initClassToolStripMenuItem_Click(object sender, EventArgs e)
 		{
 			var selectedNodes = memoryViewControl.GetSelectedNodes();
diff --git a/ReClass.NET/Memory/MemoryBuffer.cs b/ReClass.NET/Memory/MemoryBuffer.cs
index bde66ace..cb7361ec 100644
--- a/ReClass.NET/Memory/MemoryBuffer.cs
+++ b/ReClass.NET/Memory/MemoryBuffer.cs
@@ -366,12 +366,17 @@ public bool HasChanged(int offset, int length)
 
 			return false;
 		}
-
-
-		public UInt64FloatDoubleData ReadFromBuffer(int offset) => new UInt64FloatDoubleData
+		
+		public UInt64FloatDoubleData InterpretData64(int offset) => new UInt64FloatDoubleData
 																   {
 																	   Raw1 = ReadInt32(offset),
 																	   Raw2 = ReadInt32(offset + sizeof(int))
 																   };
+
+
+		public UInt32FloatData InterpretData32(int offset) => new UInt32FloatData
+															 {
+																 Raw = ReadInt32(offset)
+															 };
 	}
 }
diff --git a/ReClass.NET/Nodes/BaseHexCommentNode.cs b/ReClass.NET/Nodes/BaseHexCommentNode.cs
index da9f180e..98305d8c 100644
--- a/ReClass.NET/Nodes/BaseHexCommentNode.cs
+++ b/ReClass.NET/Nodes/BaseHexCommentNode.cs
@@ -111,7 +111,6 @@ protected int AddComment(DrawContext view, int x, int y, float fvalue, IntPtr iv
 			return x;
 		}
 
-
 		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context, IntPtr ivalue)
 		{
 			return context.Process.ReadRemoteRuntimeTypeInformation(ivalue);
diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index b5cefb00..958bf654 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -40,10 +40,10 @@ public abstract class BaseNode
 		public BaseNode ParentNode { get; internal set; }
 
 		/// <summary>Gets a value indicating whether this node is wrapped into an other node. </summary>
-		public bool IsWrapped => (ParentNode is BaseWrapperNode);
+		public bool IsWrapped => ParentNode is BaseWrapperNode;
 
 		/// <summary>All nodes that are wrapped can't be selected except classnodes because they have a context menu</summary>
-		public bool CanBeSelected => (!IsWrapped || (this is ClassNode));
+		public bool CanBeSelected => !IsWrapped || (this is ClassNode);
 
 		/// <summary>Gets or sets a value indicating whether this node is hidden.</summary>
 		public bool IsHidden { get; set; }
diff --git a/ReClass.NET/Nodes/ClassNode.cs b/ReClass.NET/Nodes/ClassNode.cs
index 05aa9077..fe51a32f 100644
--- a/ReClass.NET/Nodes/ClassNode.cs
+++ b/ReClass.NET/Nodes/ClassNode.cs
@@ -52,8 +52,7 @@ public static ClassNode Create()
 
 			return new ClassNode(true);
 		}
-
-
+		
 		/// <summary>
 		/// Initializes the class' name and vtable node from RTTI information, if it's not set already 
 		/// </summary>
@@ -72,20 +71,17 @@ public void InitFromRTTI(DrawContext context)
 			{
 				rttiInfoFromFirstNode = vtableNode.GetAssociatedRemoteRuntimeTypeInformation(context);
 			}
-			else
+			else if (firstNode is BaseHexCommentNode baseHexCommentNode)
 			{
-				if (firstNode is BaseHexCommentNode baseHexCommentNode)
+				// ask it as if it might point to a vtable
+				var value = context.Memory.InterpretData64(Offset);
+				rttiInfoFromFirstNode = baseHexCommentNode.GetAssociatedRemoteRuntimeTypeInformation(context, value.IntPtr);
+				if (!string.IsNullOrEmpty(rttiInfoFromFirstNode))
 				{
-					// ask it as if it might point to a vtable
-					var value = context.Memory.ReadFromBuffer(Offset);
-					rttiInfoFromFirstNode = baseHexCommentNode.GetAssociatedRemoteRuntimeTypeInformation(context, value.IntPtr);
-					if (!string.IsNullOrEmpty(rttiInfoFromFirstNode))
-					{
-						// convert first node to vtable node
-						var newVTableNode = BaseNode.CreateInstanceFromType(typeof(VirtualMethodTableNode));
-						var createdNodes = new List<BaseNode>();
-						this.ReplaceChildNode(firstNode, newVTableNode, ref createdNodes);
-					}
+					// convert first node to vtable node
+					var newVTableNode = BaseNode.CreateInstanceFromType(typeof(VirtualMethodTableNode));
+					var createdNodes = new List<BaseNode>();
+					this.ReplaceChildNode(firstNode, newVTableNode, ref createdNodes);
 				}
 			}
 
@@ -98,7 +94,6 @@ public void InitFromRTTI(DrawContext context)
 			this.Name = fragments[0];
 		}
 		
-
 		public override void GetUserInterfaceInfo(out string name, out Image icon)
 		{
 			throw new InvalidOperationException($"The '{nameof(ClassNode)}' node should not be accessible from the ui.");
diff --git a/ReClass.NET/Nodes/Hex32Node.cs b/ReClass.NET/Nodes/Hex32Node.cs
index c7b54027..2329c954 100644
--- a/ReClass.NET/Nodes/Hex32Node.cs
+++ b/ReClass.NET/Nodes/Hex32Node.cs
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
 
 		public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData32(Offset);
 
 			address = value.IntPtr;
 
@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 
 		public override string GetToolTipText(HotSpot spot)
 		{
-			var value = ReadFromBuffer(spot.Memory, Offset);
+			var value = spot.Memory.InterpretData32(Offset);
 
 			return $"Int32: {value.IntValue}\nUInt32: 0x{value.UIntValue:X08}\nFloat: {value.FloatValue:0.000}";
 		}
@@ -46,16 +46,11 @@ protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
 
-			var value = ReadFromBuffer(context.Memory, Offset);
+			var value = context.Memory.InterpretData32(Offset);
 
 			x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
 
 			return x;
 		}
-
-		private static UInt32FloatData ReadFromBuffer(MemoryBuffer memory, int offset) => new UInt32FloatData
-		{
-			Raw = memory.ReadInt32(offset)
-		};
 	}
 }
diff --git a/ReClass.NET/Nodes/Hex64Node.cs b/ReClass.NET/Nodes/Hex64Node.cs
index 012859ef..61749e46 100644
--- a/ReClass.NET/Nodes/Hex64Node.cs
+++ b/ReClass.NET/Nodes/Hex64Node.cs
@@ -18,7 +18,7 @@ public override void GetUserInterfaceInfo(out string name, out Image icon)
 
 		public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 		{
-			var value = spot.Memory.ReadFromBuffer(Offset);
+			var value = spot.Memory.InterpretData64(Offset);
 
 			address = value.IntPtr;
 
@@ -27,7 +27,7 @@ public override bool UseMemoryPreviewToolTip(HotSpot spot, out IntPtr address)
 
 		public override string GetToolTipText(HotSpot spot)
 		{
-			var value = spot.Memory.ReadFromBuffer(Offset);
+			var value = spot.Memory.InterpretData64(Offset);
 
 			return $"Int64: {value.LongValue}\nUInt64: 0x{value.ULongValue:X016}\nFloat: {value.FloatValue:0.000}\nDouble: {value.DoubleValue:0.000}";
 		}
@@ -46,7 +46,7 @@ protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
 
-			var value = context.Memory.ReadFromBuffer(Offset);
+			var value = context.Memory.InterpretData64(Offset);
 
 			x = AddComment(context, x, y, value.FloatValue, value.IntPtr, value.UIntPtr);
 
diff --git a/ReClass.NET/Nodes/PointerNode.cs b/ReClass.NET/Nodes/PointerNode.cs
index 47431aca..9df3b8b0 100644
--- a/ReClass.NET/Nodes/PointerNode.cs
+++ b/ReClass.NET/Nodes/PointerNode.cs
@@ -135,8 +135,7 @@ public override int CalculateDrawnHeight(DrawContext context)
 			}
 			return height;
 		}
-
-
+		
 		public override void PerformPostInitWork()
 		{
 			base.PerformPostInitWork();
diff --git a/ReClass.NET/Nodes/VirtualMethodTableNode.cs b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
index 8136a268..2c9099a0 100644
--- a/ReClass.NET/Nodes/VirtualMethodTableNode.cs
+++ b/ReClass.NET/Nodes/VirtualMethodTableNode.cs
@@ -33,8 +33,7 @@ public override void Initialize()
 				AddNode(CreateDefaultNodeForSize(IntPtr.Size));
 			}
 		}
-
-
+		
 		protected override int AddComment(DrawContext context, int x, int y)
 		{
 			x = base.AddComment(context, x, y);
@@ -49,11 +48,10 @@ protected override int AddComment(DrawContext context, int x, int y)
 			}
 			return x;
 		}
-
-
+		
 		public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context)
 		{
-			var addressFirstVTableFunction = context.Memory.ReadFromBuffer(Offset).IntPtr;
+			var addressFirstVTableFunction = context.Memory.InterpretData64(Offset).IntPtr;
 			if (addressFirstVTableFunction != IntPtr.Zero)
 			{
 				return context.Process.ReadRemoteRuntimeTypeInformation(addressFirstVTableFunction);
@@ -61,8 +59,7 @@ public string GetAssociatedRemoteRuntimeTypeInformation(DrawContext context)
 
 			return string.Empty;
 		}
-
-
+		
 		public override Size Draw(DrawContext context, int x, int y)
 		{
 			if (IsHidden && !IsWrapped)
diff --git a/ReClass.NET/Settings.cs b/ReClass.NET/Settings.cs
index 8c0ec099..32eafc3d 100644
--- a/ReClass.NET/Settings.cs
+++ b/ReClass.NET/Settings.cs
@@ -29,10 +29,7 @@ public Settings()
 									  { typeof(EnumNode), Keys.Control | Keys.Shift | Keys.E },
 									  { typeof(Int32Node), Keys.Control | Keys.Shift | Keys.I }
 								  };
-
-			// Define more here.
 		}
-
 		
 		// Application Settings
 
@@ -103,8 +100,7 @@ public Settings()
 		public Color PluginColor { get; set; } = Color.FromArgb(255, 0, 255);
 
 		public CustomDataMap CustomData { get; } = new CustomDataMap();
-
-
+		
 		public Keys GetShortcutKeyForNodeType(Type nodeType)
 		{
 			return !_shortcutKeyPerNode.TryGetValue(nodeType, out var shortcutKeys) ? Keys.None : shortcutKeys;

From 528708debe6a5a506c9174549c372f698d2345d6 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 12:19:34 +0200
Subject: [PATCH 14/15] Added undo/redo for Class AddressFormula. Wired up
 auto-exception handlers to the ShowException method in Program so it always
 catches all exceptions thrown

---
 ReClass.NET/Nodes/BaseNode.cs  |  1 -
 ReClass.NET/Nodes/ClassNode.cs | 10 +++++++++-
 ReClass.NET/Program.cs         | 18 +++++++++++++++++-
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/ReClass.NET/Nodes/BaseNode.cs b/ReClass.NET/Nodes/BaseNode.cs
index 6bb12224..edac2e11 100644
--- a/ReClass.NET/Nodes/BaseNode.cs
+++ b/ReClass.NET/Nodes/BaseNode.cs
@@ -26,7 +26,6 @@ public abstract class BaseNode
 
 		private static int nodeIndex = 0;
 
-		//private string name = string.Empty;
 		private CommandifiedMember<string, Constants.GeneralPurposeChangeType> name;
 		private string comment = string.Empty;
 
diff --git a/ReClass.NET/Nodes/ClassNode.cs b/ReClass.NET/Nodes/ClassNode.cs
index fe51a32f..d5eba916 100644
--- a/ReClass.NET/Nodes/ClassNode.cs
+++ b/ReClass.NET/Nodes/ClassNode.cs
@@ -5,6 +5,8 @@
 using System.Linq;
 using ReClassNET.Controls;
 using ReClassNET.UI;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Nodes
 {
@@ -28,7 +30,12 @@ public class ClassNode : BaseContainerNode
 
 		public Guid Uuid { get; set; }
 
-		public string AddressFormula { get; set; } = DefaultAddressFormula;
+		private CommandifiedMember<string, Constants.GeneralPurposeChangeType> addressFormula;
+		public string AddressFormula
+		{
+			get => addressFormula.MemberValue;
+			set => addressFormula.MemberValue = value;
+		}
 
 		public event NodeEventHandler NodesChanged;
 
@@ -36,6 +43,7 @@ internal ClassNode(bool notifyClassCreated)
 		{
 			Contract.Ensures(AddressFormula != null);
 
+			addressFormula = new CommandifiedMember<string, Constants.GeneralPurposeChangeType>("AddressFormula", Constants.GeneralPurposeChangeType.None, DefaultAddressFormula);
 			LevelsOpen.DefaultValue = true;
 
 			Uuid = Guid.NewGuid();
diff --git a/ReClass.NET/Program.cs b/ReClass.NET/Program.cs
index 4a1dd5d4..aba0f3f1 100644
--- a/ReClass.NET/Program.cs
+++ b/ReClass.NET/Program.cs
@@ -2,6 +2,7 @@
 using System.Diagnostics;
 using System.Drawing;
 using System.Globalization;
+using System.Threading;
 using System.Windows.Forms;
 using Microsoft.SqlServer.MessageBox;
 using ReClassNET.Core;
@@ -43,6 +44,11 @@ static void Main(string[] args)
 			DesignMode = false; // The designer doesn't call Main()
 			CommandQueueID = Guid.NewGuid();
 
+			// wire event handlers for unhandled exceptions, so these will be shown using our own method.
+			Application.SetUnhandledExceptionMode(UnhandledExceptionMode.Automatic, true);
+			Application.ThreadException += new ThreadExceptionEventHandler(Program.Application_ThreadException);
+			AppDomain.CurrentDomain.UnhandledException+=new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
+
 			CommandLineArgs = new CommandLineArgs(args);
 
 			try
@@ -107,7 +113,17 @@ static void Main(string[] args)
 
 			SettingsSerializer.Save(Settings);
 		}
-
+		
+		private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
+		{
+			ShowException(e.Exception);
+		}
+		
+		private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+		{
+			ShowException(e.ExceptionObject as Exception);
+		}
+		
 		/// <summary>Shows the exception in a special form.</summary>
 		/// <param name="ex">The exception.</param>
 		public static void ShowException(Exception ex)

From 69790cd91102a9973c3b776dcc1a78a4e82e9479 Mon Sep 17 00:00:00 2001
From: Frans Bouma <frans@sd.nl>
Date: Tue, 4 Jul 2023 16:30:30 +0200
Subject: [PATCH 15/15] Implemented class list undo/redo, and further class
 node undo/redo. Most elements are now undo/redo aware

---
 ReClass.NET/Forms/MainForm.Functions.cs  |  5 +++++
 ReClass.NET/Nodes/BaseContainerNode.cs   | 11 ++++++++--
 ReClass.NET/Project/ReClassNetProject.cs | 27 ++++++++++++++++++++++--
 3 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/ReClass.NET/Forms/MainForm.Functions.cs b/ReClass.NET/Forms/MainForm.Functions.cs
index bc668e01..d5eaeeab 100644
--- a/ReClass.NET/Forms/MainForm.Functions.cs
+++ b/ReClass.NET/Forms/MainForm.Functions.cs
@@ -319,6 +319,9 @@ public void ReplaceSelectedNodesWithType(Type type)
 					{
 						var selected = hotSpotsToReplace.Dequeue();
 
+						// Use a single command here to wrap all state changes into one single undoable object, so everything gets undone/redone in 1 go
+						var cmd = new UndoablePeriodCommand("Replace node");
+						CommandQueueManagerSingleton.GetInstance().BeginUndoablePeriod(cmd);
 						var node = BaseNode.CreateInstanceFromType(type);
 
 						var createdNodes = new List<BaseNode>();
@@ -338,6 +341,8 @@ public void ReplaceSelectedNodesWithType(Type type)
 								hotSpotsToReplace.Enqueue(new MemoryViewControl.SelectedNodeInfo(createdNode, selected.Process, selected.Memory, selected.Address + createdNode.Offset - node.Offset, selected.Level));
 							}
 						}
+						// Mark the end of the activities that have to be tracked with this single command
+						CommandQueueManagerSingleton.GetInstance().EndUndoablePeriod(cmd);
 					}
 				}
 
diff --git a/ReClass.NET/Nodes/BaseContainerNode.cs b/ReClass.NET/Nodes/BaseContainerNode.cs
index aa106dd0..1d3ec5e8 100644
--- a/ReClass.NET/Nodes/BaseContainerNode.cs
+++ b/ReClass.NET/Nodes/BaseContainerNode.cs
@@ -1,12 +1,16 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.Contracts;
+using ReClassNET.Extensions;
+using SD.Tools.Algorithmia.Commands;
+using SD.Tools.Algorithmia.GeneralDataStructures;
 
 namespace ReClassNET.Nodes
 {
 	public abstract class BaseContainerNode : BaseNode
 	{
-		private readonly List<BaseNode> nodes = new List<BaseNode>();
+		//private readonly List<BaseNode> nodes = new List<BaseNode>();
+		private readonly CommandifiedList<BaseNode> nodes = new CommandifiedList<BaseNode>();
 
 		private int updateCount;
 
@@ -262,7 +266,8 @@ protected void InsertBytes(int index, int size, ref List<BaseNode> createdNodes)
 			{
 				return;
 			}
-
+			// Mark the actions that follow as actions that have to be ignored so they're not ending up in a command's command queue
+			CommandQueueManagerSingleton.GetInstance().BeginNonUndoablePeriod();
 			while (size > 0)
 			{
 				var node = CreateDefaultNodeForSize(size);
@@ -281,6 +286,8 @@ protected void InsertBytes(int index, int size, ref List<BaseNode> createdNodes)
 
 				index++;
 			}
+			// Mark the end of the actions that have to be ignored for undo/redo
+			CommandQueueManagerSingleton.GetInstance().EndNonUndoablePeriod();
 
 			OnNodesUpdated();
 		}
diff --git a/ReClass.NET/Project/ReClassNetProject.cs b/ReClass.NET/Project/ReClassNetProject.cs
index 90f4b5ca..bd2be84b 100644
--- a/ReClass.NET/Project/ReClassNetProject.cs
+++ b/ReClass.NET/Project/ReClassNetProject.cs
@@ -1,9 +1,13 @@
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Diagnostics.Contracts;
 using System.Linq;
+using ReClassNET.Extensions;
 using ReClassNET.Nodes;
 using ReClassNET.Util;
+using SD.Tools.Algorithmia.GeneralDataStructures;
+using SD.Tools.Algorithmia.GeneralDataStructures.EventArguments;
 
 namespace ReClassNET.Project
 {
@@ -18,7 +22,7 @@ public class ReClassNetProject : IDisposable
 		public event EnumsChangedEvent EnumRemoved;
 
 		private readonly List<EnumDescription> enums = new List<EnumDescription>();
-		private readonly List<ClassNode> classes = new List<ClassNode>();
+		private readonly CommandifiedList<ClassNode> classes = new CommandifiedList<ClassNode>();		// use a commandified list for the set of classes so we get auto undo/redo tracking
 
 		public IReadOnlyList<EnumDescription> Enums => enums;
 
@@ -36,6 +40,25 @@ public class ReClassNetProject : IDisposable
 		/// List of data types to use while generating C++ code for nodes.
 		/// </summary>
 		public CppTypeMapping TypeMapping { get; } = new CppTypeMapping();
+		
+		public ReClassNetProject()
+		{
+			// We're using ListChanged instead of ElementAdding here because ListChanged is also raised when 'Redo' is executed on the list re-adding the already created element.
+			classes.ListChanged += Classes_ListChanged;
+			classes.ElementRemoved += Classes_ElementRemoved;
+		}
+
+		private void Classes_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
+		{
+			// nothing. The removed event is handled separately because ListChangedType.ItemRemoved doesn't give access to the removed element and ElementRemoved does.
+			if (e.ListChangedType == ListChangedType.ItemAdded)
+			{
+				ClassAdded?.Invoke(classes[e.NewIndex]);
+			}
+		}
+
+		private void Classes_ElementRemoved(object sender, CollectionElementRemovedEventArgs<ClassNode> e) => ClassRemoved?.Invoke(e.InvolvedElement);
+		private void Enums_ElementRemoved(object sender, CollectionElementRemovedEventArgs<EnumDescription> e) => EnumRemoved?.Invoke(e.InvolvedElement);
 
 		public void Dispose()
 		{
@@ -56,7 +79,7 @@ public void AddClass(ClassNode node)
 
 			node.NodesChanged += NodesChanged_Handler;
 
-			ClassAdded?.Invoke(node);
+			// No need to invoke the ClassAdded event here, as it's automatically raised when the class is added to the commandified list. 
 		}
 
 		public bool ContainsClass(Guid uuid)