From c543acd524828421ffe0977f2917b34210f7d583 Mon Sep 17 00:00:00 2001
From: codeimp <codeimp@e0d998f2-2e9b-42fe-843d-47128df60a06>
Date: Tue, 7 Jul 2009 11:29:56 +0000
Subject: [PATCH] Added options for selection behavior in Visual Mode and
 Classic Modes (see Preferences -> Editing)

---
 .../Plugins/BuilderModes/BuilderModes.csproj  |   3 +-
 .../ClassicModes/BrightnessMode.cs            |  88 ++---
 .../BuilderModes/ClassicModes/LinedefsMode.cs |  54 +--
 .../BuilderModes/ClassicModes/SectorsMode.cs  |  90 ++---
 .../BuilderModes/ClassicModes/ThingsMode.cs   |  38 +-
 .../BuilderModes/ClassicModes/VerticesMode.cs |  38 +-
 .../BuilderModes/General/BuilderPlug.cs       |   6 +
 .../Interface/PreferencesForm.Designer.cs     | 334 ++++++++++--------
 .../BuilderModes/Interface/PreferencesForm.cs |   4 +
 .../Interface/PreferencesForm.resx            |  48 +++
 .../VisualModes/BaseVisualGeometrySector.cs   |  12 +-
 .../VisualModes/BaseVisualGeometrySidedef.cs  |  12 +-
 .../VisualModes/BaseVisualMode.cs             |  89 +++--
 .../VisualModes/BaseVisualThing.cs            |  12 +-
 .../VisualModes/NullVisualEventReceiver.cs    | 155 ++++++++
 15 files changed, 656 insertions(+), 327 deletions(-)
 create mode 100644 Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs

diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj
index f8c7acf08..13b8af254 100644
--- a/Source/Plugins/BuilderModes/BuilderModes.csproj
+++ b/Source/Plugins/BuilderModes/BuilderModes.csproj
@@ -2,7 +2,7 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProductVersion>9.0.30729</ProductVersion>
+    <ProductVersion>8.0.50727</ProductVersion>
     <SchemaVersion>2.0</SchemaVersion>
     <ProjectGuid>{B42D5AA0-F9A6-4234-9C4B-A05B11A64851}</ProjectGuid>
     <OutputType>Library</OutputType>
@@ -250,6 +250,7 @@
     <Compile Include="FindReplace\FindThingType.cs" />
     <Compile Include="FindReplace\FindVertexNumber.cs" />
     <Compile Include="General\UndoGroup.cs" />
+    <Compile Include="VisualModes\NullVisualEventReceiver.cs" />
     <Compile Include="VisualModes\VisualActionResult.cs" />
   </ItemGroup>
   <ItemGroup>
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
index ab495997e..9f0307bdc 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
@@ -590,60 +590,64 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This is called wheh selection ends
 		protected override void OnEndMultiSelection()
 		{
-			if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
+			if(BuilderPlug.Me.AutoClearSelection ||
+			   ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)))
 			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
 				{
-					l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
-								   (l.Start.Position.y >= selectionrect.Top) &&
-								   (l.Start.Position.x <= selectionrect.Right) &&
-								   (l.Start.Position.y <= selectionrect.Bottom) &&
-								   (l.End.Position.x >= selectionrect.Left) &&
-								   (l.End.Position.y >= selectionrect.Top) &&
-								   (l.End.Position.x <= selectionrect.Right) &&
-								   (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
+									   (l.Start.Position.y >= selectionrect.Top) &&
+									   (l.Start.Position.x <= selectionrect.Right) &&
+									   (l.Start.Position.y <= selectionrect.Bottom) &&
+									   (l.End.Position.x >= selectionrect.Left) &&
+									   (l.End.Position.y >= selectionrect.Top) &&
+									   (l.End.Position.x <= selectionrect.Right) &&
+									   (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			else
-			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				else
 				{
-					l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
-								  (l.Start.Position.y >= selectionrect.Top) &&
-								  (l.Start.Position.x <= selectionrect.Right) &&
-								  (l.Start.Position.y <= selectionrect.Bottom) &&
-								  (l.End.Position.x >= selectionrect.Left) &&
-								  (l.End.Position.y >= selectionrect.Top) &&
-								  (l.End.Position.x <= selectionrect.Right) &&
-								  (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
+									  (l.Start.Position.y >= selectionrect.Top) &&
+									  (l.Start.Position.x <= selectionrect.Right) &&
+									  (l.Start.Position.y <= selectionrect.Bottom) &&
+									  (l.End.Position.x >= selectionrect.Left) &&
+									  (l.End.Position.y >= selectionrect.Top) &&
+									  (l.End.Position.x <= selectionrect.Right) &&
+									  (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			
-			// Go for all sectors
-			foreach(Sector s in General.Map.Map.Sectors)
-			{
-				// Go for all sidedefs
-				bool allselected = true;
-				foreach(Sidedef sd in s.Sidedefs)
+				
+				// Go for all sectors
+				foreach(Sector s in General.Map.Map.Sectors)
 				{
-					if(!sd.Line.Selected)
+					// Go for all sidedefs
+					bool allselected = true;
+					foreach(Sidedef sd in s.Sidedefs)
 					{
-						allselected = false;
-						break;
+						if(!sd.Line.Selected)
+						{
+							allselected = false;
+							break;
+						}
 					}
+					
+					// Sector completely selected?
+					SelectSector(s, allselected, false);
 				}
 				
-				// Sector completely selected?
-				SelectSector(s, allselected, false);
+				// Make sure all linedefs reflect selected sectors
+				foreach(Sidedef sd in General.Map.Map.Sidedefs)
+					if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected))
+						sd.Line.Selected = false;
 			}
 			
-			// Make sure all linedefs reflect selected sectors
-			foreach(Sidedef sd in General.Map.Map.Sidedefs)
-				if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected))
-					sd.Line.Selected = false;
-			
 			base.OnEndMultiSelection();
 			UpdateOverlay();
 			General.Interface.RedrawDisplay();
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index 1f1581fc9..84f3953c7 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -337,7 +337,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				editpressed = true;
 
 				// Highlighted item not selected?
-				if(!highlighted.Selected)
+				if(!highlighted.Selected && BuilderPlug.Me.AutoClearSelection)
 				{
 					// Make this the only selection
 					General.Map.Map.ClearSelectedLinedefs();
@@ -452,34 +452,38 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This is called wheh selection ends
 		protected override void OnEndMultiSelection()
 		{
-			if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
+			if(BuilderPlug.Me.AutoClearSelection ||
+			   ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)))
 			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
 				{
-					l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
-								   (l.Start.Position.y >= selectionrect.Top) &&
-								   (l.Start.Position.x <= selectionrect.Right) &&
-								   (l.Start.Position.y <= selectionrect.Bottom) &&
-								   (l.End.Position.x >= selectionrect.Left) &&
-								   (l.End.Position.y >= selectionrect.Top) &&
-								   (l.End.Position.x <= selectionrect.Right) &&
-								   (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
+									   (l.Start.Position.y >= selectionrect.Top) &&
+									   (l.Start.Position.x <= selectionrect.Right) &&
+									   (l.Start.Position.y <= selectionrect.Bottom) &&
+									   (l.End.Position.x >= selectionrect.Left) &&
+									   (l.End.Position.y >= selectionrect.Top) &&
+									   (l.End.Position.x <= selectionrect.Right) &&
+									   (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			else
-			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				else
 				{
-					l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
-								  (l.Start.Position.y >= selectionrect.Top) &&
-								  (l.Start.Position.x <= selectionrect.Right) &&
-								  (l.Start.Position.y <= selectionrect.Bottom) &&
-								  (l.End.Position.x >= selectionrect.Left) &&
-								  (l.End.Position.y >= selectionrect.Top) &&
-								  (l.End.Position.x <= selectionrect.Right) &&
-								  (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
+									  (l.Start.Position.y >= selectionrect.Top) &&
+									  (l.Start.Position.x <= selectionrect.Right) &&
+									  (l.Start.Position.y <= selectionrect.Bottom) &&
+									  (l.End.Position.x >= selectionrect.Left) &&
+									  (l.End.Position.y >= selectionrect.Top) &&
+									  (l.End.Position.x <= selectionrect.Right) &&
+									  (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
 			}
 			
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index 8450b6d3a..9bcfea4b3 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -560,7 +560,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				editpressed = true;
 
 				// Highlighted item not selected?
-				if(!highlighted.Selected)
+				if(!highlighted.Selected && BuilderPlug.Me.AutoClearSelection)
 				{
 					// Make this the only selection
 					General.Map.Map.ClearSelectedSectors();
@@ -713,60 +713,64 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This is called wheh selection ends
 		protected override void OnEndMultiSelection()
 		{
-			if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
+			if(BuilderPlug.Me.AutoClearSelection ||
+			   ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)))
 			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
 				{
-					l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
-								   (l.Start.Position.y >= selectionrect.Top) &&
-								   (l.Start.Position.x <= selectionrect.Right) &&
-								   (l.Start.Position.y <= selectionrect.Bottom) &&
-								   (l.End.Position.x >= selectionrect.Left) &&
-								   (l.End.Position.y >= selectionrect.Top) &&
-								   (l.End.Position.x <= selectionrect.Right) &&
-								   (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected |= ((l.Start.Position.x >= selectionrect.Left) &&
+									   (l.Start.Position.y >= selectionrect.Top) &&
+									   (l.Start.Position.x <= selectionrect.Right) &&
+									   (l.Start.Position.y <= selectionrect.Bottom) &&
+									   (l.End.Position.x >= selectionrect.Left) &&
+									   (l.End.Position.y >= selectionrect.Top) &&
+									   (l.End.Position.x <= selectionrect.Right) &&
+									   (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			else
-			{
-				// Go for all lines
-				foreach(Linedef l in General.Map.Map.Linedefs)
+				else
 				{
-					l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
-								  (l.Start.Position.y >= selectionrect.Top) &&
-								  (l.Start.Position.x <= selectionrect.Right) &&
-								  (l.Start.Position.y <= selectionrect.Bottom) &&
-								  (l.End.Position.x >= selectionrect.Left) &&
-								  (l.End.Position.y >= selectionrect.Top) &&
-								  (l.End.Position.x <= selectionrect.Right) &&
-								  (l.End.Position.y <= selectionrect.Bottom));
+					// Go for all lines
+					foreach(Linedef l in General.Map.Map.Linedefs)
+					{
+						l.Selected = ((l.Start.Position.x >= selectionrect.Left) &&
+									  (l.Start.Position.y >= selectionrect.Top) &&
+									  (l.Start.Position.x <= selectionrect.Right) &&
+									  (l.Start.Position.y <= selectionrect.Bottom) &&
+									  (l.End.Position.x >= selectionrect.Left) &&
+									  (l.End.Position.y >= selectionrect.Top) &&
+									  (l.End.Position.x <= selectionrect.Right) &&
+									  (l.End.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			
-			// Go for all sectors
-			foreach(Sector s in General.Map.Map.Sectors)
-			{
-				// Go for all sidedefs
-				bool allselected = true;
-				foreach(Sidedef sd in s.Sidedefs)
+				
+				// Go for all sectors
+				foreach(Sector s in General.Map.Map.Sectors)
 				{
-					if(!sd.Line.Selected)
+					// Go for all sidedefs
+					bool allselected = true;
+					foreach(Sidedef sd in s.Sidedefs)
 					{
-						allselected = false;
-						break;
+						if(!sd.Line.Selected)
+						{
+							allselected = false;
+							break;
+						}
 					}
+					
+					// Sector completely selected?
+					SelectSector(s, allselected, false);
 				}
 				
-				// Sector completely selected?
-				SelectSector(s, allselected, false);
+				// Make sure all linedefs reflect selected sectors
+				foreach(Sidedef sd in General.Map.Map.Sidedefs)
+					if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected))
+						sd.Line.Selected = false;
 			}
 			
-			// Make sure all linedefs reflect selected sectors
-			foreach(Sidedef sd in General.Map.Map.Sidedefs)
-				if(!sd.Sector.Selected && ((sd.Other == null) || !sd.Other.Sector.Selected))
-					sd.Line.Selected = false;
-			
 			base.OnEndMultiSelection();
 			if(renderer.StartOverlay(true)) renderer.Finish();
 			General.Interface.RedrawDisplay();
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index 2daeb498c..4f1bd69cf 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -312,7 +312,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				editpressed = true;
 				
 				// Highlighted item not selected?
-				if(!highlighted.Selected)
+				if(!highlighted.Selected && BuilderPlug.Me.AutoClearSelection)
 				{
 					// Make this the only selection
 					General.Map.Map.ClearSelectedThings();
@@ -439,26 +439,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This is called wheh selection ends
 		protected override void OnEndMultiSelection()
 		{
-			if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
+			if(BuilderPlug.Me.AutoClearSelection ||
+			   ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)))
 			{
-				// Go for all things
-				foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
+				if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
 				{
-					t.Selected |= ((t.Position.x >= selectionrect.Left) &&
-								   (t.Position.y >= selectionrect.Top) &&
-								   (t.Position.x <= selectionrect.Right) &&
-								   (t.Position.y <= selectionrect.Bottom));
+					// Go for all things
+					foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
+					{
+						t.Selected |= ((t.Position.x >= selectionrect.Left) &&
+									   (t.Position.y >= selectionrect.Top) &&
+									   (t.Position.x <= selectionrect.Right) &&
+									   (t.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			else
-			{
-				// Go for all things
-				foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
+				else
 				{
-					t.Selected = ((t.Position.x >= selectionrect.Left) &&
-								  (t.Position.y >= selectionrect.Top) &&
-								  (t.Position.x <= selectionrect.Right) &&
-								  (t.Position.y <= selectionrect.Bottom));
+					// Go for all things
+					foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
+					{
+						t.Selected = ((t.Position.x >= selectionrect.Left) &&
+									  (t.Position.y >= selectionrect.Top) &&
+									  (t.Position.x <= selectionrect.Right) &&
+									  (t.Position.y <= selectionrect.Bottom));
+					}
 				}
 			}
 			
diff --git a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
index d5cb0c3ff..d631f1b11 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
@@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				editpressed = true;
 
 				// Highlighted item not selected?
-				if(!highlighted.Selected)
+				if(!highlighted.Selected && BuilderPlug.Me.AutoClearSelection)
 				{
 					// Make this the only selection
 					General.Map.Map.ClearSelectedVertices();
@@ -406,26 +406,30 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This is called wheh selection ends
 		protected override void OnEndMultiSelection()
 		{
-			if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
+			if(BuilderPlug.Me.AutoClearSelection ||
+			   ((Math.Abs(base.selectionrect.Width) > 0.1f) && (Math.Abs(base.selectionrect.Height) > 0.1f)))
 			{
-				// Go for all vertices
-				foreach(Vertex v in General.Map.Map.Vertices)
+				if(General.Interface.ShiftState ^ BuilderPlug.Me.AdditiveSelect)
 				{
-					v.Selected |= ((v.Position.x >= selectionrect.Left) &&
-								   (v.Position.y >= selectionrect.Top) &&
-								   (v.Position.x <= selectionrect.Right) &&
-								   (v.Position.y <= selectionrect.Bottom));
+					// Go for all vertices
+					foreach(Vertex v in General.Map.Map.Vertices)
+					{
+						v.Selected |= ((v.Position.x >= selectionrect.Left) &&
+									   (v.Position.y >= selectionrect.Top) &&
+									   (v.Position.x <= selectionrect.Right) &&
+									   (v.Position.y <= selectionrect.Bottom));
+					}
 				}
-			}
-			else
-			{
-				// Go for all vertices
-				foreach(Vertex v in General.Map.Map.Vertices)
+				else
 				{
-					v.Selected = ((v.Position.x >= selectionrect.Left) &&
-								  (v.Position.y >= selectionrect.Top) &&
-								  (v.Position.x <= selectionrect.Right) &&
-								  (v.Position.y <= selectionrect.Bottom));
+					// Go for all vertices
+					foreach(Vertex v in General.Map.Map.Vertices)
+					{
+						v.Selected = ((v.Position.x >= selectionrect.Left) &&
+									  (v.Position.y >= selectionrect.Top) &&
+									  (v.Position.x <= selectionrect.Right) &&
+									  (v.Position.y <= selectionrect.Bottom));
+					}
 				}
 			}
 			
diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs
index 77e94ccc6..d2773c561 100644
--- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs
+++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs
@@ -65,6 +65,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private bool editnewthing;
 		private bool editnewsector;
 		private bool additiveselect;
+		private bool autoclearselection;
+		private bool visualmodeclearselection;
 		private string copiedtexture;
 		private string copiedflat;
 		private Point copiedoffsets;
@@ -97,6 +99,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public bool EditNewThing { get { return editnewthing; } }
 		public bool EditNewSector { get { return editnewsector; } }
 		public bool AdditiveSelect { get { return additiveselect; } }
+		public bool AutoClearSelection { get { return autoclearselection; } }
+		public bool VisualModeClearSelection { get { return visualmodeclearselection; } }
 		public string CopiedTexture { get { return copiedtexture; } set { copiedtexture = value; } }
 		public string CopiedFlat { get { return copiedflat; } set { copiedflat = value; } }
 		public Point CopiedOffsets { get { return copiedoffsets; } set { copiedoffsets = value; } }
@@ -172,6 +176,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			editnewthing = General.Settings.ReadPluginSetting("editnewthing", true);
 			editnewsector = General.Settings.ReadPluginSetting("editnewsector", false);
 			additiveselect = General.Settings.ReadPluginSetting("additiveselect", false);
+			autoclearselection = General.Settings.ReadPluginSetting("autoclearselection", true);
+			visualmodeclearselection = General.Settings.ReadPluginSetting("visualmodeclearselection", false);
 			viewselectionnumbers = General.Settings.ReadPluginSetting("viewselectionnumbers", true);
 			stitchrange = (float)General.Settings.ReadPluginSetting("stitchrange", 20);
 			highlightrange = (float)General.Settings.ReadPluginSetting("highlightrange", 20);
diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
index 51650c9d3..bc08264e2 100644
--- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.Designer.cs
@@ -30,31 +30,33 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			this.tabs = new System.Windows.Forms.TabControl();
 			this.taboptions = new System.Windows.Forms.TabPage();
-			this.label8 = new System.Windows.Forms.Label();
-			this.label9 = new System.Windows.Forms.Label();
-			this.label6 = new System.Windows.Forms.Label();
-			this.label7 = new System.Windows.Forms.Label();
-			this.label4 = new System.Windows.Forms.Label();
-			this.label5 = new System.Windows.Forms.Label();
-			this.label3 = new System.Windows.Forms.Label();
-			this.label2 = new System.Windows.Forms.Label();
-			this.additiveselect = new System.Windows.Forms.CheckBox();
-			this.editnewsector = new System.Windows.Forms.CheckBox();
+			this.groupBox3 = new System.Windows.Forms.GroupBox();
+			this.visualmodeclearselection = new System.Windows.Forms.CheckBox();
+			this.autoclearselection = new System.Windows.Forms.CheckBox();
 			this.editnewthing = new System.Windows.Forms.CheckBox();
-			this.heightbysidedef = new System.Windows.Forms.ComboBox();
-			this.label1 = new System.Windows.Forms.Label();
-			this.groupBox1 = new System.Windows.Forms.GroupBox();
+			this.editnewsector = new System.Windows.Forms.CheckBox();
+			this.additiveselect = new System.Windows.Forms.CheckBox();
 			this.groupBox2 = new System.Windows.Forms.GroupBox();
-			this.groupBox3 = new System.Windows.Forms.GroupBox();
 			this.stitchrange = new CodeImp.DoomBuilder.Controls.NumericTextbox();
+			this.label8 = new System.Windows.Forms.Label();
+			this.label2 = new System.Windows.Forms.Label();
 			this.splitlinedefsrange = new CodeImp.DoomBuilder.Controls.NumericTextbox();
+			this.label3 = new System.Windows.Forms.Label();
+			this.label9 = new System.Windows.Forms.Label();
+			this.label5 = new System.Windows.Forms.Label();
+			this.label6 = new System.Windows.Forms.Label();
 			this.highlightrange = new CodeImp.DoomBuilder.Controls.NumericTextbox();
 			this.highlightthingsrange = new CodeImp.DoomBuilder.Controls.NumericTextbox();
+			this.label4 = new System.Windows.Forms.Label();
+			this.label7 = new System.Windows.Forms.Label();
+			this.groupBox1 = new System.Windows.Forms.GroupBox();
+			this.label1 = new System.Windows.Forms.Label();
+			this.heightbysidedef = new System.Windows.Forms.ComboBox();
 			this.tabs.SuspendLayout();
 			this.taboptions.SuspendLayout();
-			this.groupBox1.SuspendLayout();
-			this.groupBox2.SuspendLayout();
 			this.groupBox3.SuspendLayout();
+			this.groupBox2.SuspendLayout();
+			this.groupBox1.SuspendLayout();
 			this.SuspendLayout();
 			// 
 			// tabs
@@ -84,146 +86,69 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.taboptions.Text = "Editing";
 			this.taboptions.UseVisualStyleBackColor = true;
 			// 
-			// label8
-			// 
-			this.label8.AutoSize = true;
-			this.label8.Location = new System.Drawing.Point(232, 130);
-			this.label8.Name = "label8";
-			this.label8.Size = new System.Drawing.Size(35, 14);
-			this.label8.TabIndex = 15;
-			this.label8.Text = "pixels";
-			// 
-			// label9
-			// 
-			this.label9.AutoSize = true;
-			this.label9.Location = new System.Drawing.Point(47, 130);
-			this.label9.Name = "label9";
-			this.label9.Size = new System.Drawing.Size(103, 14);
-			this.label9.TabIndex = 13;
-			this.label9.Text = "Split linedefs within:";
-			this.label9.TextAlign = System.Drawing.ContentAlignment.TopRight;
-			// 
-			// label6
-			// 
-			this.label6.AutoSize = true;
-			this.label6.Location = new System.Drawing.Point(232, 66);
-			this.label6.Name = "label6";
-			this.label6.Size = new System.Drawing.Size(35, 14);
-			this.label6.TabIndex = 12;
-			this.label6.Text = "pixels";
-			// 
-			// label7
-			// 
-			this.label7.AutoSize = true;
-			this.label7.Location = new System.Drawing.Point(36, 66);
-			this.label7.Name = "label7";
-			this.label7.Size = new System.Drawing.Size(114, 14);
-			this.label7.TabIndex = 10;
-			this.label7.Text = "Highlight things within:";
-			this.label7.TextAlign = System.Drawing.ContentAlignment.TopRight;
-			// 
-			// label4
-			// 
-			this.label4.AutoSize = true;
-			this.label4.Location = new System.Drawing.Point(232, 34);
-			this.label4.Name = "label4";
-			this.label4.Size = new System.Drawing.Size(35, 14);
-			this.label4.TabIndex = 9;
-			this.label4.Text = "pixels";
-			// 
-			// label5
-			// 
-			this.label5.AutoSize = true;
-			this.label5.Location = new System.Drawing.Point(20, 34);
-			this.label5.Name = "label5";
-			this.label5.Size = new System.Drawing.Size(130, 14);
-			this.label5.TabIndex = 7;
-			this.label5.Text = "Highlight geometry within:";
-			this.label5.TextAlign = System.Drawing.ContentAlignment.TopRight;
-			// 
-			// label3
-			// 
-			this.label3.AutoSize = true;
-			this.label3.Location = new System.Drawing.Point(232, 98);
-			this.label3.Name = "label3";
-			this.label3.Size = new System.Drawing.Size(35, 14);
-			this.label3.TabIndex = 6;
-			this.label3.Text = "pixels";
-			// 
-			// label2
+			// groupBox3
 			// 
-			this.label2.AutoSize = true;
-			this.label2.Location = new System.Drawing.Point(33, 98);
-			this.label2.Name = "label2";
-			this.label2.Size = new System.Drawing.Size(117, 14);
-			this.label2.TabIndex = 4;
-			this.label2.Text = "Stitch geometry within:";
-			this.label2.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			this.groupBox3.Controls.Add(this.visualmodeclearselection);
+			this.groupBox3.Controls.Add(this.autoclearselection);
+			this.groupBox3.Controls.Add(this.editnewthing);
+			this.groupBox3.Controls.Add(this.editnewsector);
+			this.groupBox3.Controls.Add(this.additiveselect);
+			this.groupBox3.Location = new System.Drawing.Point(308, 90);
+			this.groupBox3.Name = "groupBox3";
+			this.groupBox3.Size = new System.Drawing.Size(332, 171);
+			this.groupBox3.TabIndex = 18;
+			this.groupBox3.TabStop = false;
+			this.groupBox3.Text = " Options ";
 			// 
-			// additiveselect
+			// visualmodeclearselection
 			// 
-			this.additiveselect.AutoSize = true;
-			this.additiveselect.Location = new System.Drawing.Point(28, 89);
-			this.additiveselect.Name = "additiveselect";
-			this.additiveselect.Size = new System.Drawing.Size(211, 18);
-			this.additiveselect.TabIndex = 3;
-			this.additiveselect.Text = "Additive selecting without holding shift";
-			this.additiveselect.UseVisualStyleBackColor = true;
+			this.visualmodeclearselection.AutoSize = true;
+			this.visualmodeclearselection.Location = new System.Drawing.Point(23, 129);
+			this.visualmodeclearselection.Name = "visualmodeclearselection";
+			this.visualmodeclearselection.Size = new System.Drawing.Size(220, 18);
+			this.visualmodeclearselection.TabIndex = 5;
+			this.visualmodeclearselection.Text = "Automatic clear selection in Visual Mode";
+			this.visualmodeclearselection.UseVisualStyleBackColor = true;
 			// 
-			// editnewsector
+			// autoclearselection
 			// 
-			this.editnewsector.AutoSize = true;
-			this.editnewsector.Location = new System.Drawing.Point(28, 61);
-			this.editnewsector.Name = "editnewsector";
-			this.editnewsector.Size = new System.Drawing.Size(271, 18);
-			this.editnewsector.TabIndex = 2;
-			this.editnewsector.Text = "Edit sector properties when drawing a new sector";
-			this.editnewsector.UseVisualStyleBackColor = true;
+			this.autoclearselection.AutoSize = true;
+			this.autoclearselection.Location = new System.Drawing.Point(23, 105);
+			this.autoclearselection.Name = "autoclearselection";
+			this.autoclearselection.Size = new System.Drawing.Size(231, 18);
+			this.autoclearselection.TabIndex = 4;
+			this.autoclearselection.Text = "Automatic clear selection in Classic Modes";
+			this.autoclearselection.UseVisualStyleBackColor = true;
 			// 
 			// editnewthing
 			// 
 			this.editnewthing.AutoSize = true;
-			this.editnewthing.Location = new System.Drawing.Point(28, 33);
+			this.editnewthing.Location = new System.Drawing.Point(23, 33);
 			this.editnewthing.Name = "editnewthing";
 			this.editnewthing.Size = new System.Drawing.Size(256, 18);
 			this.editnewthing.TabIndex = 1;
 			this.editnewthing.Text = "Edit thing properties when inserting a new thing";
 			this.editnewthing.UseVisualStyleBackColor = true;
 			// 
-			// heightbysidedef
-			// 
-			this.heightbysidedef.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-			this.heightbysidedef.FormattingEnabled = true;
-			this.heightbysidedef.Items.AddRange(new object[] {
-            "Do nothing",
-            "Change the ceiling height",
-            "Change the floor height",
-            "Change both floor and ceiling height"});
-			this.heightbysidedef.Location = new System.Drawing.Point(364, 32);
-			this.heightbysidedef.Name = "heightbysidedef";
-			this.heightbysidedef.Size = new System.Drawing.Size(199, 22);
-			this.heightbysidedef.TabIndex = 0;
-			// 
-			// label1
+			// editnewsector
 			// 
-			this.label1.AutoSize = true;
-			this.label1.Location = new System.Drawing.Point(29, 35);
-			this.label1.Name = "label1";
-			this.label1.Size = new System.Drawing.Size(315, 14);
-			this.label1.TabIndex = 0;
-			this.label1.Text = "When sector height changes are used on a wall in Visual Mode:";
-			this.label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			this.editnewsector.AutoSize = true;
+			this.editnewsector.Location = new System.Drawing.Point(23, 57);
+			this.editnewsector.Name = "editnewsector";
+			this.editnewsector.Size = new System.Drawing.Size(271, 18);
+			this.editnewsector.TabIndex = 2;
+			this.editnewsector.Text = "Edit sector properties when drawing a new sector";
+			this.editnewsector.UseVisualStyleBackColor = true;
 			// 
-			// groupBox1
+			// additiveselect
 			// 
-			this.groupBox1.Controls.Add(this.label1);
-			this.groupBox1.Controls.Add(this.heightbysidedef);
-			this.groupBox1.Location = new System.Drawing.Point(6, 6);
-			this.groupBox1.Name = "groupBox1";
-			this.groupBox1.Size = new System.Drawing.Size(634, 78);
-			this.groupBox1.TabIndex = 16;
-			this.groupBox1.TabStop = false;
-			this.groupBox1.Text = " Behavior ";
+			this.additiveselect.AutoSize = true;
+			this.additiveselect.Location = new System.Drawing.Point(23, 81);
+			this.additiveselect.Name = "additiveselect";
+			this.additiveselect.Size = new System.Drawing.Size(211, 18);
+			this.additiveselect.TabIndex = 3;
+			this.additiveselect.Text = "Additive selecting without holding shift";
+			this.additiveselect.UseVisualStyleBackColor = true;
 			// 
 			// groupBox2
 			// 
@@ -246,18 +171,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.groupBox2.TabStop = false;
 			this.groupBox2.Text = " Ranges ";
 			// 
-			// groupBox3
-			// 
-			this.groupBox3.Controls.Add(this.editnewthing);
-			this.groupBox3.Controls.Add(this.editnewsector);
-			this.groupBox3.Controls.Add(this.additiveselect);
-			this.groupBox3.Location = new System.Drawing.Point(308, 90);
-			this.groupBox3.Name = "groupBox3";
-			this.groupBox3.Size = new System.Drawing.Size(332, 171);
-			this.groupBox3.TabIndex = 18;
-			this.groupBox3.TabStop = false;
-			this.groupBox3.Text = " Options ";
-			// 
 			// stitchrange
 			// 
 			this.stitchrange.AllowDecimal = false;
@@ -270,6 +183,25 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.stitchrange.Size = new System.Drawing.Size(59, 20);
 			this.stitchrange.TabIndex = 5;
 			// 
+			// label8
+			// 
+			this.label8.AutoSize = true;
+			this.label8.Location = new System.Drawing.Point(232, 130);
+			this.label8.Name = "label8";
+			this.label8.Size = new System.Drawing.Size(35, 14);
+			this.label8.TabIndex = 15;
+			this.label8.Text = "pixels";
+			// 
+			// label2
+			// 
+			this.label2.AutoSize = true;
+			this.label2.Location = new System.Drawing.Point(33, 98);
+			this.label2.Name = "label2";
+			this.label2.Size = new System.Drawing.Size(117, 14);
+			this.label2.TabIndex = 4;
+			this.label2.Text = "Stitch geometry within:";
+			this.label2.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			// 
 			// splitlinedefsrange
 			// 
 			this.splitlinedefsrange.AllowDecimal = false;
@@ -282,6 +214,44 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.splitlinedefsrange.Size = new System.Drawing.Size(59, 20);
 			this.splitlinedefsrange.TabIndex = 14;
 			// 
+			// label3
+			// 
+			this.label3.AutoSize = true;
+			this.label3.Location = new System.Drawing.Point(232, 98);
+			this.label3.Name = "label3";
+			this.label3.Size = new System.Drawing.Size(35, 14);
+			this.label3.TabIndex = 6;
+			this.label3.Text = "pixels";
+			// 
+			// label9
+			// 
+			this.label9.AutoSize = true;
+			this.label9.Location = new System.Drawing.Point(47, 130);
+			this.label9.Name = "label9";
+			this.label9.Size = new System.Drawing.Size(103, 14);
+			this.label9.TabIndex = 13;
+			this.label9.Text = "Split linedefs within:";
+			this.label9.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			// 
+			// label5
+			// 
+			this.label5.AutoSize = true;
+			this.label5.Location = new System.Drawing.Point(20, 34);
+			this.label5.Name = "label5";
+			this.label5.Size = new System.Drawing.Size(130, 14);
+			this.label5.TabIndex = 7;
+			this.label5.Text = "Highlight geometry within:";
+			this.label5.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			// 
+			// label6
+			// 
+			this.label6.AutoSize = true;
+			this.label6.Location = new System.Drawing.Point(232, 66);
+			this.label6.Name = "label6";
+			this.label6.Size = new System.Drawing.Size(35, 14);
+			this.label6.TabIndex = 12;
+			this.label6.Text = "pixels";
+			// 
 			// highlightrange
 			// 
 			this.highlightrange.AllowDecimal = false;
@@ -306,6 +276,60 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.highlightthingsrange.Size = new System.Drawing.Size(59, 20);
 			this.highlightthingsrange.TabIndex = 11;
 			// 
+			// label4
+			// 
+			this.label4.AutoSize = true;
+			this.label4.Location = new System.Drawing.Point(232, 34);
+			this.label4.Name = "label4";
+			this.label4.Size = new System.Drawing.Size(35, 14);
+			this.label4.TabIndex = 9;
+			this.label4.Text = "pixels";
+			// 
+			// label7
+			// 
+			this.label7.AutoSize = true;
+			this.label7.Location = new System.Drawing.Point(36, 66);
+			this.label7.Name = "label7";
+			this.label7.Size = new System.Drawing.Size(114, 14);
+			this.label7.TabIndex = 10;
+			this.label7.Text = "Highlight things within:";
+			this.label7.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			// 
+			// groupBox1
+			// 
+			this.groupBox1.Controls.Add(this.label1);
+			this.groupBox1.Controls.Add(this.heightbysidedef);
+			this.groupBox1.Location = new System.Drawing.Point(6, 6);
+			this.groupBox1.Name = "groupBox1";
+			this.groupBox1.Size = new System.Drawing.Size(634, 78);
+			this.groupBox1.TabIndex = 16;
+			this.groupBox1.TabStop = false;
+			this.groupBox1.Text = " Behavior ";
+			// 
+			// label1
+			// 
+			this.label1.AutoSize = true;
+			this.label1.Location = new System.Drawing.Point(29, 35);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(315, 14);
+			this.label1.TabIndex = 0;
+			this.label1.Text = "When sector height changes are used on a wall in Visual Mode:";
+			this.label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
+			// 
+			// heightbysidedef
+			// 
+			this.heightbysidedef.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+			this.heightbysidedef.FormattingEnabled = true;
+			this.heightbysidedef.Items.AddRange(new object[] {
+            "Do nothing",
+            "Change the ceiling height",
+            "Change the floor height",
+            "Change both floor and ceiling height"});
+			this.heightbysidedef.Location = new System.Drawing.Point(364, 32);
+			this.heightbysidedef.Name = "heightbysidedef";
+			this.heightbysidedef.Size = new System.Drawing.Size(199, 22);
+			this.heightbysidedef.TabIndex = 0;
+			// 
 			// PreferencesForm
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
@@ -320,12 +344,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.Text = "PreferencesForm";
 			this.tabs.ResumeLayout(false);
 			this.taboptions.ResumeLayout(false);
-			this.groupBox1.ResumeLayout(false);
-			this.groupBox1.PerformLayout();
-			this.groupBox2.ResumeLayout(false);
-			this.groupBox2.PerformLayout();
 			this.groupBox3.ResumeLayout(false);
 			this.groupBox3.PerformLayout();
+			this.groupBox2.ResumeLayout(false);
+			this.groupBox2.PerformLayout();
+			this.groupBox1.ResumeLayout(false);
+			this.groupBox1.PerformLayout();
 			this.ResumeLayout(false);
 
 		}
@@ -354,5 +378,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private System.Windows.Forms.GroupBox groupBox1;
 		private System.Windows.Forms.GroupBox groupBox3;
 		private System.Windows.Forms.GroupBox groupBox2;
+		private System.Windows.Forms.CheckBox autoclearselection;
+		private System.Windows.Forms.CheckBox visualmodeclearselection;
 	}
 }
\ No newline at end of file
diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs
index f6d034d32..f2d315803 100644
--- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs
+++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.cs
@@ -64,6 +64,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			highlightrange.Text = General.Settings.ReadPluginSetting("highlightrange", 20).ToString();
 			highlightthingsrange.Text = General.Settings.ReadPluginSetting("highlightthingsrange", 10).ToString();
 			splitlinedefsrange.Text = General.Settings.ReadPluginSetting("splitlinedefsrange", 10).ToString();
+			autoclearselection.Checked = BuilderPlug.Me.AutoClearSelection;
+			visualmodeclearselection.Checked = BuilderPlug.Me.VisualModeClearSelection;
 		}
 
 		#endregion
@@ -82,6 +84,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			General.Settings.WritePluginSetting("highlightrange", highlightrange.GetResult(0));
 			General.Settings.WritePluginSetting("highlightthingsrange", highlightthingsrange.GetResult(0));
 			General.Settings.WritePluginSetting("splitlinedefsrange", splitlinedefsrange.GetResult(0));
+			General.Settings.WritePluginSetting("autoclearselection", autoclearselection.Checked);
+			General.Settings.WritePluginSetting("visualmodeclearselection", visualmodeclearselection.Checked);
 		}
 		
 		// When Cancel is pressed on the preferences dialog
diff --git a/Source/Plugins/BuilderModes/Interface/PreferencesForm.resx b/Source/Plugins/BuilderModes/Interface/PreferencesForm.resx
index fa16e8259..1e71088b0 100644
--- a/Source/Plugins/BuilderModes/Interface/PreferencesForm.resx
+++ b/Source/Plugins/BuilderModes/Interface/PreferencesForm.resx
@@ -126,6 +126,12 @@
   <metadata name="groupBox3.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
+  <metadata name="visualmodeclearselection.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="autoclearselection.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
   <metadata name="editnewthing.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
@@ -183,6 +189,48 @@
   <metadata name="heightbysidedef.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
+  <metadata name="stitchrange.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label8.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label2.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="splitlinedefsrange.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label3.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label9.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label5.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label6.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="highlightrange.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="highlightthingsrange.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label4.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label7.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="label1.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="heightbysidedef.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
   <metadata name="$this.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
index f7347809e..d787c4ea4 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
@@ -102,8 +102,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Select or deselect
 		public virtual void OnSelectEnd()
 		{
-			this.selected = !this.selected;
-			mode.SelectionChanged = true;
+			if(this.selected)
+			{
+				this.selected = false;
+				mode.RemoveSelectedObject(this);
+			}
+			else
+			{
+				this.selected = true;
+				mode.AddSelectedObject(this);
+			}
 		}
 		
 		// Processing
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
index 8f908fd57..2fc9247f5 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
@@ -526,8 +526,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			else
 			{
 				// Add/remove selection
-				this.selected = !this.selected;
-				mode.SelectionChanged = true;
+				if(this.selected)
+				{
+					this.selected = false;
+					mode.RemoveSelectedObject(this);
+				}
+				else
+				{
+					this.selected = true;
+					mode.AddSelectedObject(this);
+				}
 			}
 		}
 		
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index a37619fd8..2d742bc9d 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -131,6 +131,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			// Initialize
 			this.gravity = new Vector3D(0.0f, 0.0f, 0.0f);
+			this.selectedobjects = new List<IVisualEventReceiver>();
 			
 			// We have no destructor
 			GC.SuppressFinalize(this);
@@ -153,6 +154,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		
 		#region ================== Methods
 		
+		// This adds a selected object
+		internal void AddSelectedObject(IVisualEventReceiver obj)
+		{
+			selectedobjects.Add(obj);
+			selectionchanged = true;
+		}
+		
+		// This removes a selected object
+		internal void RemoveSelectedObject(IVisualEventReceiver obj)
+		{
+			selectedobjects.Remove(obj);
+			selectionchanged = true;
+		}
+		
 		// This is called before an action is performed
 		public void PreAction(int multiselectionundogroup)
 		{
@@ -162,12 +177,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// If the action is not performed on a selected object, clear the
 			// current selection and make a temporary selection for the target.
-			if((target.picked != null) && !target.picked.Selected)
+			if((target.picked != null) && !target.picked.Selected && (BuilderPlug.Me.VisualModeClearSelection || (selectedobjects.Count == 0)))
 			{
 				// Single object, no selection
 				singleselection = true;
 				ClearSelection();
 				target.picked.Selected = true;
+				selectedobjects.Add(target.picked as IVisualEventReceiver);
 				undocreated = false;
 			}
 			else
@@ -190,17 +206,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					undocreated = true;
 				}
 			}
-			
-			MakeSelectedObjectsList();
 		}
 
-		// Called before an action is performed. This does not make an undo level or change selection.
+		// Called before an action is performed. This does not make an undo level
 		private void PreActionNoChange()
 		{
 			actionresult = new VisualActionResult();
 			singleselection = false;
 			undocreated = false;
-			MakeSelectedObjectsList();
 		}
 		
 		// This is called after an action is performed
@@ -266,7 +279,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 
 		// This makes a list of the selected object
-		private void MakeSelectedObjectsList()
+		private void RebuildSelectedObjectsList()
 		{
 			// Make list of selected objects
 			selectedobjects = new List<IVisualEventReceiver>();
@@ -615,18 +628,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnMouseMove(e);
+			GetTargetEventReceiver(true).OnMouseMove(e);
 		}
 		
 		// Undo performed
 		public override void OnUndoEnd()
 		{
 			base.OnUndoEnd();
-
+			RebuildSelectedObjectsList();
+			
 			// We can't group with this undo level anymore
 			lastundogroup = UndoGroup.None;
 		}
 		
+		// Redo performed
+		public override void OnRedoEnd()
+		{
+			base.OnRedoEnd();
+			RebuildSelectedObjectsList();
+		}
+		
 		#endregion
 
 		#region ================== Action Assist
@@ -774,7 +795,31 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			}
 			return things;
 		}
-
+		
+		// This returns the IVisualEventReceiver on which the action must be performed
+		private IVisualEventReceiver GetTargetEventReceiver(bool targetonly)
+		{
+			if(target.picked != null)
+			{
+				if(singleselection || target.picked.Selected || targetonly)
+				{
+					return (IVisualEventReceiver)target.picked;
+				}
+				else if(selectedobjects.Count > 0)
+				{
+					return selectedobjects[0];
+				}
+				else
+				{
+					return (IVisualEventReceiver)target.picked;
+				}
+			}
+			else
+			{
+				return new NullVisualEventReceiver();
+			}
+		}
+		
 		#endregion
 
 		#region ================== Actions
@@ -811,7 +856,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			PreActionNoChange();
 			PickTargetUnlocked();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectBegin();
+			GetTargetEventReceiver(true).OnSelectBegin();
 			PostAction();
 		}
 
@@ -819,7 +864,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void EndSelect()
 		{
 			PreActionNoChange();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectEnd();
+			GetTargetEventReceiver(true).OnSelectEnd();
 			PostAction();
 		}
 
@@ -827,7 +872,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void BeginEdit()
 		{
 			PreAction(UndoGroup.None);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnEditBegin();
+			GetTargetEventReceiver(false).OnEditBegin();
 			PostAction();
 		}
 
@@ -835,7 +880,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void EndEdit()
 		{
 			PreAction(UndoGroup.None);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnEditEnd();
+			GetTargetEventReceiver(false).OnEditEnd();
 			PostAction();
 		}
 
@@ -964,7 +1009,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			PreAction(UndoGroup.None);
 			renderer.SetCrosshairBusy(true);
 			General.Interface.RedrawDisplay();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnSelectTexture();
+			GetTargetEventReceiver(false).OnSelectTexture();
 			UpdateChangedObjects();
 			renderer.SetCrosshairBusy(false);
 			PostAction();
@@ -974,7 +1019,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void TextureCopy()
 		{
 			PreActionNoChange();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyTexture();
+			GetTargetEventReceiver(false).OnCopyTexture();
 			PostAction();
 		}
 
@@ -992,7 +1037,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			PreAction(UndoGroup.None);
 			renderer.SetCrosshairBusy(true);
 			General.Interface.RedrawDisplay();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureAlign(true, false);
+			GetTargetEventReceiver(false).OnTextureAlign(true, false);
 			UpdateChangedObjects();
 			renderer.SetCrosshairBusy(false);
 			PostAction();
@@ -1004,7 +1049,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			PreAction(UndoGroup.None);
 			renderer.SetCrosshairBusy(true);
 			General.Interface.RedrawDisplay();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureAlign(false, true);
+			GetTargetEventReceiver(false).OnTextureAlign(false, true);
 			UpdateChangedObjects();
 			renderer.SetCrosshairBusy(false);
 			PostAction();
@@ -1014,7 +1059,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ToggleUpperUnpegged()
 		{
 			PreAction(UndoGroup.None);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnToggleUpperUnpegged();
+			GetTargetEventReceiver(false).OnToggleUpperUnpegged();
 			PostAction();
 		}
 
@@ -1022,7 +1067,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ToggleLowerUnpegged()
 		{
 			PreAction(UndoGroup.None);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnToggleLowerUnpegged();
+			GetTargetEventReceiver(false).OnToggleLowerUnpegged();
 			PostAction();
 		}
 
@@ -1054,7 +1099,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void FloodfillTextures()
 		{
 			PreAction(UndoGroup.None);
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnTextureFloodfill();
+			GetTargetEventReceiver(false).OnTextureFloodfill();
 			PostAction();
 		}
 
@@ -1062,7 +1107,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void TextureCopyOffsets()
 		{
 			PreActionNoChange();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyTextureOffsets();
+			GetTargetEventReceiver(false).OnCopyTextureOffsets();
 			PostAction();
 		}
 
@@ -1078,7 +1123,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void CopyProperties()
 		{
 			PreActionNoChange();
-			if(target.picked != null) (target.picked as IVisualEventReceiver).OnCopyProperties();
+			GetTargetEventReceiver(false).OnCopyProperties();
 			PostAction();
 		}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
index f813ab7f8..a2984bfd8 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
@@ -381,8 +381,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Select or deselect
 		public virtual void OnSelectEnd()
 		{
-			this.selected = !this.selected;
-			mode.SelectionChanged = true;
+			if(this.selected)
+			{
+				this.selected = false;
+				mode.RemoveSelectedObject(this);
+			}
+			else
+			{
+				this.selected = true;
+				mode.AddSelectedObject(this);
+			}
 		}
 		
 		// Copy properties
diff --git a/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs b/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs
new file mode 100644
index 000000000..62f0cd6db
--- /dev/null
+++ b/Source/Plugins/BuilderModes/VisualModes/NullVisualEventReceiver.cs
@@ -0,0 +1,155 @@
+
+#region ================== Copyright (c) 2007 Pascal vd Heiden
+
+/*
+ * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
+ * This program is released under GNU General Public License
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ */
+
+#endregion
+
+#region ================== Namespaces
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.Windows.Forms;
+using System.IO;
+using System.Reflection;
+using CodeImp.DoomBuilder.Windows;
+using CodeImp.DoomBuilder.IO;
+using CodeImp.DoomBuilder.Map;
+using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.Geometry;
+using CodeImp.DoomBuilder.Editing;
+using CodeImp.DoomBuilder.VisualModes;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.BuilderModes
+{
+	// This doesn't do jack shit.
+	internal class NullVisualEventReceiver : IVisualEventReceiver
+	{
+		public NullVisualEventReceiver()
+		{
+		}
+		
+		public void OnSelectBegin()
+		{
+		}
+
+		public void OnSelectEnd()
+		{
+		}
+
+		public void OnEditBegin()
+		{
+		}
+
+		public void OnEditEnd()
+		{
+		}
+
+		public void OnMouseMove(MouseEventArgs e)
+		{
+		}
+
+		public void OnChangeTargetHeight(int amount)
+		{
+		}
+
+		public void OnChangeTargetBrightness(bool up)
+		{
+		}
+
+		public void OnChangeTextureOffset(int horizontal, int vertical)
+		{
+		}
+
+		public void OnResetTextureOffset()
+		{
+		}
+
+		public void OnSelectTexture()
+		{
+		}
+
+		public void OnCopyTexture()
+		{
+		}
+
+		public void OnPasteTexture()
+		{
+		}
+
+		public void OnCopyTextureOffsets()
+		{
+		}
+
+		public void OnPasteTextureOffsets()
+		{
+		}
+
+		public void OnCopyProperties()
+		{
+		}
+
+		public void OnPasteProperties()
+		{
+		}
+
+		public void OnTextureAlign(bool alignx, bool aligny)
+		{
+		}
+
+		public void OnTextureFloodfill()
+		{
+		}
+
+		public void OnToggleUpperUnpegged()
+		{
+		}
+
+		public void OnToggleLowerUnpegged()
+		{
+		}
+
+		public void OnProcess(double deltatime)
+		{
+		}
+
+		public void OnInsert()
+		{
+		}
+
+		public void OnDelete()
+		{
+		}
+
+		public void ApplyTexture(string texture)
+		{
+		}
+
+		public void ApplyUpperUnpegged(bool set)
+		{
+		}
+
+		public void ApplyLowerUnpegged(bool set)
+		{
+		}
+
+		public string GetTextureName()
+		{
+			return "";
+		}
+	}
+}
-- 
GitLab