From 4920091e71b08aedc2bcbb34841a560f288fdd0b Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Tue, 29 Dec 2015 11:44:32 +0000
Subject: [PATCH] Fixed a crash after pressing "Edit Selection" button in the
 Find and Replace window when several instances of the same map element were
 selected. Redesigned the Test Map button's drop-down: test engines are now
 shown and behave the same way as skills and also have appropriate icons.

---
 Source/Core/GZBuilder/Data/EngineInfo.cs      | 22 ++++++
 Source/Core/Windows/MainForm.cs               | 68 +++++++++----------
 Source/Core/Windows/SectorEditFormUDMF.cs     |  3 +-
 .../FindReplace/BaseFindLinedef.cs            |  5 +-
 .../FindReplace/BaseFindSector.cs             |  5 +-
 .../FindReplace/BaseFindSidedef.cs            |  5 +-
 .../BuilderModes/FindReplace/BaseFindThing.cs |  5 +-
 .../FindReplace/FindVertexNumber.cs           | 17 +----
 8 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/Source/Core/GZBuilder/Data/EngineInfo.cs b/Source/Core/GZBuilder/Data/EngineInfo.cs
index 17a1470e6..f090e396d 100644
--- a/Source/Core/GZBuilder/Data/EngineInfo.cs
+++ b/Source/Core/GZBuilder/Data/EngineInfo.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Drawing;
 using System.IO;
 
 namespace CodeImp.DoomBuilder.GZBuilder.Data 
@@ -14,6 +15,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 		public bool CustomParameters;
 		public int TestSkill;
 		public bool TestShortPaths;
+		private Bitmap icon;
+		public Bitmap TestProgramIcon { get { return icon; } }
 
 		public EngineInfo() 
 		{
@@ -28,6 +31,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 			CustomParameters = other.CustomParameters;
 			TestSkill = other.TestSkill;
 			TestShortPaths = other.TestShortPaths;
+			icon = other.icon;
 		}
 
 		private void CheckProgramName() 
@@ -37,6 +41,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 				//get engine name from path
 				testprogramname = Path.GetFileNameWithoutExtension(TestProgram);
 			}
+
+			// Update icon
+			if(icon != null)
+			{
+				icon.Dispose();
+				icon = null;
+			}
+
+			if(File.Exists(TestProgram))
+			{
+				Icon i = Icon.ExtractAssociatedIcon(TestProgram);
+				if(i != null) icon = i.ToBitmap();
+			}
+			
+			if(icon == null)
+			{
+				icon = new Bitmap(16, 16);
+			}
 		}
 	}
 }
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index b4aad6949..d1085a1dc 100644
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -127,9 +127,6 @@ namespace CodeImp.DoomBuilder.Windows
 		private bool mouseexclusive;
 		private int mouseexclusivebreaklevel;
 		
-		// Skills
-		private ToolStripItem[] skills;
-		
 		// Last info on panels
 		private object lastinfoobject;
 		
@@ -1488,63 +1485,62 @@ namespace CodeImp.DoomBuilder.Windows
 			// Map loaded?
 			if(General.Map != null)
 			{
-				// Make the new skills list
-				skills = new ToolStripItem[(General.Map.Config.Skills.Count * 2) + 3]; //mxd
-
-				//mxd. Add engine selector
-				ToolStripMenuItem menuitem = new ToolStripMenuItem("Engine:", Resources.Marine);
-				for(int i = 0; i < General.Map.ConfigSettings.TestEngines.Count; i++) 
-				{
-					ToolStripMenuItem engineItem = new ToolStripMenuItem(General.Map.ConfigSettings.TestEngines[i].TestProgramName);
-					engineItem.Tag = i;
-					engineItem.Checked = (i == General.Map.ConfigSettings.CurrentEngineIndex);
-					engineItem.Click += engineItem_Click;
-					menuitem.DropDownItems.Add(engineItem);
-				}
-				skills[0] = menuitem;
-				
-				//mxd. Add seperator
-				skills[1] = new ToolStripSeparator();
-				skills[1].Padding = new Padding(0, 3, 0, 3);
-				int addindex = 2;
+				// Make the new items list
+				ToolStripItem[] items = new ToolStripItem[(General.Map.Config.Skills.Count * 2) + General.Map.ConfigSettings.TestEngines.Count + 2]; //mxd
+				int addindex = 0;
 				
 				// Positive skills are with monsters
-				for(int i = 0; i < General.Map.Config.Skills.Count; i++)
+				foreach(SkillInfo si in General.Map.Config.Skills)
 				{
-					menuitem = new ToolStripMenuItem(General.Map.Config.Skills[i].ToString());
+					ToolStripMenuItem menuitem = new ToolStripMenuItem(si.ToString());
 					menuitem.Image = Resources.Monster2;
 					menuitem.Click += TestSkill_Click;
-					menuitem.Tag = General.Map.Config.Skills[i].Index;
-					menuitem.Checked = (General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == General.Map.Config.Skills[i].Index));
-					skills[addindex++] = menuitem;
+					menuitem.Tag = si.Index;
+					menuitem.Checked = (General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
+					items[addindex++] = menuitem;
 				}
 
 				// Add seperator
-				skills[addindex] = new ToolStripSeparator();
-				skills[addindex].Padding = new Padding(0, 3, 0, 3);
+				items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) };
 				addindex++;
 
 				// Negative skills are without monsters
-				for(int i = 0; i < General.Map.Config.Skills.Count; i++)
+				foreach(SkillInfo si in General.Map.Config.Skills)
 				{
-					menuitem = new ToolStripMenuItem(General.Map.Config.Skills[i].ToString());
+					ToolStripMenuItem menuitem = new ToolStripMenuItem(si.ToString());
 					menuitem.Image = Resources.Monster3;
 					menuitem.Click += TestSkill_Click;
-					menuitem.Tag = -General.Map.Config.Skills[i].Index;
-					menuitem.Checked = (!General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == General.Map.Config.Skills[i].Index));
-					skills[addindex++] = menuitem;
+					menuitem.Tag = -si.Index;
+					menuitem.Checked = (!General.Settings.TestMonsters && (General.Map.ConfigSettings.TestSkill == si.Index));
+					items[addindex++] = menuitem;
+				}
+
+				//mxd. Add seperator
+				items[addindex] = new ToolStripSeparator { Padding = new Padding(0, 3, 0, 3) };
+				addindex++;
+
+				//mxd. Add test engines
+				for(int i = 0; i < General.Map.ConfigSettings.TestEngines.Count; i++)
+				{
+					ToolStripMenuItem menuitem = new ToolStripMenuItem(General.Map.ConfigSettings.TestEngines[i].TestProgramName);
+					menuitem.Image = General.Map.ConfigSettings.TestEngines[i].TestProgramIcon;
+					menuitem.Click += TestEngine_Click;
+					menuitem.Tag = i;
+					menuitem.Checked = (i == General.Map.ConfigSettings.CurrentEngineIndex);
+					items[addindex++] = menuitem;
 				}
 				
 				// Add to list
-				buttontest.DropDownItems.AddRange(skills);
+				buttontest.DropDownItems.AddRange(items);
 			}
 		}
 
 		//mxd
-		private void engineItem_Click(object sender, EventArgs e)
+		private void TestEngine_Click(object sender, EventArgs e)
 		{
 			General.Map.ConfigSettings.CurrentEngineIndex = (int)(((ToolStripMenuItem)sender).Tag);
 			General.Map.ConfigSettings.Changed = true;
+			General.Map.Launcher.TestAtSkill(General.Map.ConfigSettings.TestSkill);
 			UpdateSkills();
 		}
 		
diff --git a/Source/Core/Windows/SectorEditFormUDMF.cs b/Source/Core/Windows/SectorEditFormUDMF.cs
index 014d55022..149673ac2 100644
--- a/Source/Core/Windows/SectorEditFormUDMF.cs
+++ b/Source/Core/Windows/SectorEditFormUDMF.cs
@@ -499,11 +499,12 @@ namespace CodeImp.DoomBuilder.Windows
 			
 			foreach(Sector s in sectors)
 			{
+				if(slopepivots.ContainsKey(s)) continue;
 				Vector2D pivot = new Vector2D(s.BBox.X + s.BBox.Width / 2, s.BBox.Y + s.BBox.Height / 2);
 				globalslopepivot += pivot;
 				slopepivots.Add(s, pivot);
 
-				//mxd. Store initial properties
+				// Store initial properties
 				sectorprops.Add(s, new SectorProperties(s));
 			}
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindLinedef.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindLinedef.cs
index c6087c6e3..467ebbf72 100644
--- a/Source/Plugins/BuilderModes/FindReplace/BaseFindLinedef.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindLinedef.cs
@@ -40,8 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Edit objects
 		public override void EditObjects(FindReplaceObject[] selection) 
 		{
-			List<Linedef> linedefs = new List<Linedef>(selection.Length);
-			foreach(FindReplaceObject o in selection) linedefs.Add(o.Linedef);
+			HashSet<Linedef> linedefs = new HashSet<Linedef>();
+			foreach(FindReplaceObject o in selection)
+				if(!linedefs.Contains(o.Linedef)) linedefs.Add(o.Linedef);
 			General.Interface.ShowEditLinedefs(linedefs);
 		}
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindSector.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindSector.cs
index a5b06a7e6..5405192e2 100644
--- a/Source/Plugins/BuilderModes/FindReplace/BaseFindSector.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindSector.cs
@@ -53,8 +53,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Edit objects
 		public override void EditObjects(FindReplaceObject[] selection) 
 		{
-			List<Sector> sectors = new List<Sector>(selection.Length);
-			foreach(FindReplaceObject o in selection) sectors.Add(o.Sector);
+			HashSet<Sector> sectors = new HashSet<Sector>();
+			foreach(FindReplaceObject o in selection) 
+				if(!sectors.Contains(o.Sector)) sectors.Add(o.Sector);
 			General.Interface.ShowEditSectors(sectors);
 		}
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindSidedef.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindSidedef.cs
index 0f175e1b3..45c59cd0e 100644
--- a/Source/Plugins/BuilderModes/FindReplace/BaseFindSidedef.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindSidedef.cs
@@ -40,8 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Edit objects
 		public override void EditObjects(FindReplaceObject[] selection) 
 		{
-			List<Linedef> linedefs = new List<Linedef>(selection.Length);
-			foreach(FindReplaceObject o in selection) linedefs.Add(o.Sidedef.Line);
+			HashSet<Linedef> linedefs = new HashSet<Linedef>();
+			foreach(FindReplaceObject o in selection)
+				if(!linedefs.Contains(o.Sidedef.Line)) linedefs.Add(o.Sidedef.Line);
 			General.Interface.ShowEditLinedefs(linedefs);
 		}
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/BaseFindThing.cs b/Source/Plugins/BuilderModes/FindReplace/BaseFindThing.cs
index a6d0bba23..5af3c7f85 100644
--- a/Source/Plugins/BuilderModes/FindReplace/BaseFindThing.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/BaseFindThing.cs
@@ -40,8 +40,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Edit objects
 		public override void EditObjects(FindReplaceObject[] selection) 
 		{
-			List<Thing> things = new List<Thing>(selection.Length);
-			foreach(FindReplaceObject o in selection) things.Add(o.Thing);
+			HashSet<Thing> things = new HashSet<Thing>();
+			foreach(FindReplaceObject o in selection) 
+				if(!things.Contains(o.Thing)) things.Add(o.Thing);
 			General.Interface.ShowEditThings(things);
 		}
 
diff --git a/Source/Plugins/BuilderModes/FindReplace/FindVertexNumber.cs b/Source/Plugins/BuilderModes/FindReplace/FindVertexNumber.cs
index 7300ea49c..d743da112 100644
--- a/Source/Plugins/BuilderModes/FindReplace/FindVertexNumber.cs
+++ b/Source/Plugins/BuilderModes/FindReplace/FindVertexNumber.cs
@@ -41,18 +41,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		#region ================== Constructor / Destructor
 
-		// Constructor
-		public FindVertexNumber()
-		{
-			// Initialize
-
-		}
-
-		// Destructor
-		~FindVertexNumber()
-		{
-		}
-
 		#endregion
 
 		#region ================== Methods
@@ -108,8 +96,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Edit objects
 		public override void EditObjects(FindReplaceObject[] selection)
 		{
-			List<Vertex> vertices = new List<Vertex>(selection.Length);
-			foreach(FindReplaceObject o in selection) vertices.Add(o.Vertex);
+			HashSet<Vertex> vertices = new HashSet<Vertex>();
+			foreach(FindReplaceObject o in selection)
+				if(!vertices.Contains(o.Vertex)) vertices.Add(o.Vertex);
 			General.Interface.ShowEditVertices(vertices);
 			General.Map.Map.Update();
 		}
-- 
GitLab