From cb1eb1de831d4b0cf18a724bb7cb279f5d79813d Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Sun, 19 Jun 2016 00:09:53 +0000
Subject: [PATCH] Changed, Visual mode: "Paste Selection" action (Ctrl-V) can
 now paste both copied textures and things, based on what was copied last.
 Changed, Map Analysis mode: the view is now much more zoomed after clocking
 on a "Check very short linedefs" error check result. Removed single testing
 engine launchable by the editor at once limitation (it worked properly only
 when using Test map actions anyway). Fixed: re-did the fix for invalid
 geometry created when drawing very large grids from R2653, because it caused
 other issues.

---
 Source/Core/Editing/ClassicMode.cs            |   2 +-
 Source/Core/GZBuilder/Data/EngineInfo.cs      |   2 +-
 Source/Core/General/Launcher.cs               | 101 +++++++++++-------
 Source/Core/Geometry/Tools.cs                 |  11 +-
 Source/Core/Map/MapSet.cs                     |   2 +-
 .../Interface/MenusForm.Designer.cs           |   2 +-
 .../ErrorChecks/ResultShortLinedef.cs         |  16 ++-
 .../VisualModes/BaseVisualMode.cs             |  14 ++-
 8 files changed, 91 insertions(+), 59 deletions(-)

diff --git a/Source/Core/Editing/ClassicMode.cs b/Source/Core/Editing/ClassicMode.cs
index 805e34552..88feca7ea 100644
--- a/Source/Core/Editing/ClassicMode.cs
+++ b/Source/Core/Editing/ClassicMode.cs
@@ -722,7 +722,7 @@ namespace CodeImp.DoomBuilder.Editing
 
 				if(s == null)
 				{
-					General.MainWindow.DisplayStatus(StatusType.Warning, "Can't test from current position: cursor is not inside sector!");
+					General.MainWindow.DisplayStatus(StatusType.Warning, "Can't test from current position: mouse cursor must be inside a sector!");
 					return false;
 				}
 
diff --git a/Source/Core/GZBuilder/Data/EngineInfo.cs b/Source/Core/GZBuilder/Data/EngineInfo.cs
index 1fe74f440..fe333438f 100644
--- a/Source/Core/GZBuilder/Data/EngineInfo.cs
+++ b/Source/Core/GZBuilder/Data/EngineInfo.cs
@@ -96,7 +96,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 			if(File.Exists(testprogram))
 			{
 				Icon i = Icon.ExtractAssociatedIcon(testprogram);
-				icon = (i != null ? i.ToBitmap() : new Bitmap(Properties.Resources.Question));
+				icon = new Bitmap(i != null ? i.ToBitmap() : Properties.Resources.Question);
 			}
 			else
 			{
diff --git a/Source/Core/General/Launcher.cs b/Source/Core/General/Launcher.cs
index 43e2d1e95..387446506 100644
--- a/Source/Core/General/Launcher.cs
+++ b/Source/Core/General/Launcher.cs
@@ -17,6 +17,7 @@
 #region ================== Namespaces
 
 using System;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 using System.Windows.Forms;
@@ -39,10 +40,10 @@ namespace CodeImp.DoomBuilder
 		#region ================== Variables
 
 		private string tempwad;
-		private Process process; //mxd
+		private Dictionary<Process, string> processes; //mxd
 		private bool isdisposed;
 
-		delegate void EngineExitedCallback(); //mxd
+		delegate void EngineExitedCallback(Process p); //mxd
 		
 		#endregion
 
@@ -59,6 +60,7 @@ namespace CodeImp.DoomBuilder
 		{
 			// Initialize
 			CleanTempFile(manager);
+			processes = new Dictionary<Process, string>(); //mxd
 
 			// Bind actions
 			General.Actions.BindMethods(this);
@@ -73,16 +75,30 @@ namespace CodeImp.DoomBuilder
 				// Unbind actions
 				General.Actions.UnbindMethods(this);
 
-				//mxd. Terminate process?
-				if(process != null) 
+				//mxd. Terminate running processes?
+				if(processes != null) 
 				{
-					process.CloseMainWindow();
-					process.Close();
+					foreach(KeyValuePair<Process, string> group in processes)
+					{
+						// Close engine
+						group.Key.CloseMainWindow();
+						group.Key.Close();
+
+						// Remove temporary file
+						if(File.Exists(group.Value))
+						{
+							try { File.Delete(group.Value); }
+							catch { }
+						}
+					}
 				}
 				
 				// Remove temporary file
-				try { File.Delete(tempwad); }
-				catch(Exception) { }
+				if(File.Exists(tempwad))
+				{
+					try { File.Delete(tempwad); }
+					catch { }
+				}
 				
 				// Done
 				isdisposed = true;
@@ -232,18 +248,6 @@ namespace CodeImp.DoomBuilder
 			return outp;
 		}
 
-		//mxd
-		private bool AlreadyTesting()
-		{
-			if(process != null)
-			{
-				General.ShowWarningMessage("Game engine is already running." + Environment.NewLine + "Please close \"" + process.MainModule.FileName + "\" first.", MessageBoxButtons.OK);
-				return true;
-			}
-
-			return false;
-		}
-
 		#endregion
 
 		#region ================== Test
@@ -252,23 +256,22 @@ namespace CodeImp.DoomBuilder
 		[BeginAction("testmap")]
 		public void Test()
 		{
-			if(AlreadyTesting() || !General.Editing.Mode.OnMapTestBegin(false)) return; //mxd
-			TestAtSkill(General.Map.ConfigSettings.TestSkill);
-			General.Editing.Mode.OnMapTestEnd(false); //mxd
+			TestAtSkill(General.Map.ConfigSettings.TestSkill, false);
 		}
 
 		//mxd
 		[BeginAction("testmapfromview")]
 		public void TestFromView() 
 		{
-			if(AlreadyTesting() || !General.Editing.Mode.OnMapTestBegin(true)) return;
-			TestAtSkill(General.Map.ConfigSettings.TestSkill);
-			General.Editing.Mode.OnMapTestEnd(true);
+			TestAtSkill(General.Map.ConfigSettings.TestSkill, true);
 		}
 		
 		// This saves the map to a temporary file and launches a test with the given skill
-		public void TestAtSkill(int skill)
+		public void TestAtSkill(int skill) { TestAtSkill(skill, false); }
+		public void TestAtSkill(int skill, bool testfromcurrentposition)
 		{
+			if(!General.Editing.Mode.OnMapTestBegin(testfromcurrentposition)) return; //mxd
+			
 			Cursor oldcursor = Cursor.Current;
 
 			// Check if configuration is OK
@@ -301,8 +304,11 @@ namespace CodeImp.DoomBuilder
 			}
 			
 			// Remove temporary file
-			try { File.Delete(tempwad); }
-			catch(Exception) { }
+			if(File.Exists(tempwad) && !processes.ContainsValue(tempwad))
+			{
+				try { File.Delete(tempwad); }
+				catch { }
+			}
 			
 			// Save map to temporary file
 			Cursor.Current = Cursors.WaitCursor;
@@ -334,9 +340,10 @@ namespace CodeImp.DoomBuilder
 					try
 					{
 						// Start the program
-						process = Process.Start(processinfo);
+						Process process = Process.Start(processinfo);
 						process.EnableRaisingEvents = true; //mxd
 						process.Exited += ProcessOnExited; //mxd
+						processes.Add(process, tempwad); //mxd
 						Cursor.Current = oldcursor; //mxd
 					}
 					catch(Exception e)
@@ -351,16 +358,33 @@ namespace CodeImp.DoomBuilder
 				}
 			}
 			General.Plugins.OnMapSaveEnd(SavePurpose.Testing);
+			General.Editing.Mode.OnMapTestEnd(testfromcurrentposition); //mxd
 		}
 
 		//mxd
-		private void TestingFinished() 
+		private void TestingFinished(Process process) 
 		{
 			// Done
 			TimeSpan deltatime = TimeSpan.FromTicks(process.ExitTime.Ticks - process.StartTime.Ticks);
-			process = null;
-			General.WriteLogLine("Test program has finished.");
+			General.WriteLogLine("Testing with \"" + process.StartInfo.FileName + "\" has finished.");
 			General.WriteLogLine("Run time: " + deltatime.TotalSeconds.ToString("###########0.00") + " seconds");
+
+			//mxd. Remove from active processes list
+			string closedtempfile = processes[process];
+			processes.Remove(process);
+
+			//mxd. Still have running engines?..
+			if(processes.Count > 0)
+			{
+				// Remove temp file
+				if(File.Exists(closedtempfile))
+				{
+					try { File.Delete(closedtempfile); }
+					catch { }
+				}
+				return; 
+			}
+			
 			General.MainWindow.DisplayReady();
 
 			// Clean up temp file
@@ -374,20 +398,15 @@ namespace CodeImp.DoomBuilder
 					General.Map.Graphics.Reset();
 					General.MainWindow.RedrawDisplay();
 				}
-				/*else if(General.Editing.Mode is VisualMode)
-				{
-					General.MainWindow.StopExclusiveMouseInput();
-					General.MainWindow.StartExclusiveMouseInput();
-				}*/
 			}
 
 			General.MainWindow.FocusDisplay();
 		}
 
 		//mxd
-		private void ProcessOnExited(object sender, EventArgs eventArgs) 
+		private void ProcessOnExited(object sender, EventArgs e)
 		{
-			General.MainWindow.Invoke(new EngineExitedCallback(TestingFinished));
+			General.MainWindow.Invoke(new EngineExitedCallback(TestingFinished), new[] { sender });
 		}
 
 		// This deletes the previous temp file and creates a new, empty temp file
@@ -395,7 +414,7 @@ namespace CodeImp.DoomBuilder
 		{
 			// Remove temporary file
 			try { File.Delete(tempwad); }
-			catch(Exception) { }
+			catch { }
 			
 			// Make new empty temp file
 			tempwad = General.MakeTempFilename(manager.TempPath, "wad");
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index 02775481f..80cfbc286 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -937,7 +937,6 @@ namespace CodeImp.DoomBuilder.Geometry
 				if(points[0].stitch) mergeverts.Add(v1); else nonmergeverts.Add(v1);
 
 				// Go for all other points
-				int roundprecision = (General.Map.FormatInterface.VertexDecimals > 0 ? General.Map.FormatInterface.VertexDecimals - 1 : 0); //mxd
 				for(int i = 1; i < points.Count; i++)
 				{
 					// Create vertex for point
@@ -963,7 +962,7 @@ namespace CodeImp.DoomBuilder.Geometry
 						// Check if any other lines intersect this line
 						List<float> intersections = new List<float>();
 						Line2D measureline = ld.Line;
-						Dictionary<Linedef, bool> processed = new Dictionary<Linedef, bool>(); //mxd
+						HashSet<Linedef> processed = new HashSet<Linedef>(); //mxd
 
 						//mxd
 						foreach(Sector s in map.Sectors) 
@@ -973,7 +972,7 @@ namespace CodeImp.DoomBuilder.Geometry
 							{
 								foreach(Sidedef side in s.Sidedefs) 
 								{
-									if(processed.ContainsKey(side.Line)) continue;
+									if(processed.Contains(side.Line)) continue;
 									if(side.Line == ld) continue;
 
 									float u;
@@ -983,7 +982,7 @@ namespace CodeImp.DoomBuilder.Geometry
 										intersections.Add(u);
 									}
 
-									processed.Add(side.Line, false);
+									processed.Add(side.Line);
 								}
 							}
 						}
@@ -1000,10 +999,6 @@ namespace CodeImp.DoomBuilder.Geometry
 							// may already have changed in length due to a previous split
 							Vector2D splitpoint = measureline.GetCoordinatesAt(u);
 
-							//mxd. Work around some imprecisions when splitting very long lines (like 19000 mu long)
-							splitpoint.x = (float)Math.Round(splitpoint.x, roundprecision);
-							splitpoint.y = (float)Math.Round(splitpoint.y, roundprecision);
-
 							// Make the vertex
 							Vertex splitvertex = map.CreateVertex(splitpoint);
 							if(splitvertex == null) return false;
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index c2f1bc2d1..b1b8eb252 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -46,7 +46,7 @@ namespace CodeImp.DoomBuilder.Map
 
 		/// <summary>Stiching distance. This is only to get around inaccuracies. Basically,
 		/// geometry only stitches when exactly on top of each other.</summary>
-		public const float STITCH_DISTANCE = 0.001f;
+		public const float STITCH_DISTANCE = 0.005f; //mxd. 0.001f is not enough when drawing very long lines...
 		
 		// Virtual sector identification
 		// This contains a character that is invalid in the UDMF standard, but valid
diff --git a/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs b/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
index 5e7e03dd1..e4a3d5cc4 100644
--- a/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
+++ b/Source/Plugins/AutomapMode/Interface/MenusForm.Designer.cs
@@ -91,7 +91,7 @@
             "Hexen",
             "Strife"});
 			this.colorpreset.Name = "colorpreset";
-			this.colorpreset.Size = new System.Drawing.Size(121, 25);
+			this.colorpreset.Size = new System.Drawing.Size(75, 25);
 			this.colorpreset.SelectedIndexChanged += new System.EventHandler(this.colorpreset_SelectedIndexChanged);
 			// 
 			// MenusForm
diff --git a/Source/Plugins/BuilderModes/ErrorChecks/ResultShortLinedef.cs b/Source/Plugins/BuilderModes/ErrorChecks/ResultShortLinedef.cs
index 7b2db8aa6..03f54ee96 100644
--- a/Source/Plugins/BuilderModes/ErrorChecks/ResultShortLinedef.cs
+++ b/Source/Plugins/BuilderModes/ErrorChecks/ResultShortLinedef.cs
@@ -1,6 +1,7 @@
 #region ================== Namespaces
 
 using System;
+using System.Drawing;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Rendering;
 
@@ -50,7 +51,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This must return the string that is displayed in the listbox
 		public override string ToString()
 		{
-			return "Linedef " + line.Index + " is shorter than 1 m.u.";
+			return "Linedef " + line.Index + " is shorter than 1 mu.";
 		}
 		
 		// Rendering
@@ -60,6 +61,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			renderer.PlotVertex(line.Start, ColorCollection.VERTICES);
 			renderer.PlotVertex(line.End, ColorCollection.VERTICES);
 		}
+
+		// We must zoom in way more than usual...
+		public override RectangleF GetZoomArea()
+		{
+			// Get Area
+			RectangleF area = base.GetZoomArea();
+
+			// Remove padding
+			area.Inflate(-97f, -97f);
+
+			// Return area
+			return area;
+		}
 		
 		#endregion
 	}
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index 9512836a2..862403e3e 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -2702,7 +2702,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void TextureCopy()
 		{
 			PreActionNoChange();
-			GetTargetEventReceiver(true).OnCopyTexture(); //mxd
+			IVisualEventReceiver i = GetTargetEventReceiver(true);
+			i.OnCopyTexture(); //mxd
+			if(!(i is VisualThing)) copybuffer.Clear(); //mxd. Not copying things any more...
 			PostAction();
 		}
 
@@ -3119,7 +3121,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				VisualThing vt = (VisualThing)i;
 				if(vt != null) copybuffer.Add(new ThingCopyData(vt.Thing));
 			}
-			General.Interface.DisplayStatus(StatusType.Info, "Copied " + copybuffer.Count + " Things");
+
+			string rest = copybuffer.Count + (copybuffer.Count > 1 ? " things." : " thing.");
+			General.Interface.DisplayStatus(StatusType.Info, "Copied " + rest);
 		}
 
 		//mxd
@@ -3129,7 +3133,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			CopySelection();
 
 			//Create undo
-			string rest = copybuffer.Count + " thing" + (copybuffer.Count > 1 ? "s." : ".");
+			string rest = copybuffer.Count + (copybuffer.Count > 1 ? " things." : " thing.");
 			CreateUndo("Cut " + rest);
 			General.Interface.DisplayStatus(StatusType.Info, "Cut " + rest);
 
@@ -3155,7 +3159,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(copybuffer.Count == 0)
 			{
-				General.Interface.DisplayStatus(StatusType.Warning, "Nothing to paste, cut or copy some Things first!");
+				TexturePaste(); // I guess we may paste a texture or two instead
 				return;
 			}
 			
@@ -3167,7 +3171,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				return;
 			}
 
-			string rest = copybuffer.Count + " thing" + (copybuffer.Count > 1 ? "s" : "");
+			string rest = copybuffer.Count + (copybuffer.Count > 1 ? " things." : " thing.");
 			General.Map.UndoRedo.CreateUndo("Paste " + rest);
 			General.Interface.DisplayStatus(StatusType.Info, "Pasted " + rest);
 			
-- 
GitLab