From 6326adc9ed547d197b3473e1e713461a65cc264f Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Tue, 9 Jul 2013 11:29:10 +0000
Subject: [PATCH] Sector Edit form now works in realtime mode in Doom/Hexen map
 formats. Status text now displays info about current selection. Removed
 StairSectorBuilder plugin. The version form doombuilder.com works fine with
 current version of GZDB.

---
 Source/Core/Controls/ButtonsNumericTextbox.cs |   2 +-
 Source/Core/Controls/ImageSelectorControl.cs  |  10 +-
 .../Controls/LinedefInfoPanel.Designer.cs     |  24 +-
 Source/Core/Controls/LinedefInfoPanel.resx    |  18 +-
 .../Core/Controls/SectorInfoPanel.Designer.cs |  28 +--
 Source/Core/Windows/MainForm.cs               |  17 +-
 .../Core/Windows/SectorEditForm.Designer.cs   |   6 +
 Source/Core/Windows/SectorEditForm.cs         | 212 +++++++++++++++---
 Source/Core/Windows/StatusInfo.cs             |   5 +
 .../ClassicModes/BaseClassicMode.cs           |  17 ++
 .../BuilderModes/ClassicModes/LinedefsMode.cs |  22 ++
 .../BuilderModes/ClassicModes/SectorsMode.cs  |  35 ++-
 .../BuilderModes/ClassicModes/ThingsMode.cs   |  17 ++
 .../BuilderModes/ClassicModes/VerticesMode.cs |  27 ++-
 .../VisualModes/BaseVisualGeometrySector.cs   |  29 ++-
 .../VisualModes/BaseVisualMode.cs             |  61 ++++-
 16 files changed, 429 insertions(+), 101 deletions(-)

diff --git a/Source/Core/Controls/ButtonsNumericTextbox.cs b/Source/Core/Controls/ButtonsNumericTextbox.cs
index e71271454..b5c9fbf72 100644
--- a/Source/Core/Controls/ButtonsNumericTextbox.cs
+++ b/Source/Core/Controls/ButtonsNumericTextbox.cs
@@ -150,7 +150,7 @@ namespace CodeImp.DoomBuilder.Controls
 			}
 			else
 			{
-				buttons.Value += Math.Sign(e.Delta) * 1;
+				buttons.Value -= Math.Sign(e.Delta);
 			}
 		}
 
diff --git a/Source/Core/Controls/ImageSelectorControl.cs b/Source/Core/Controls/ImageSelectorControl.cs
index 715ce871f..d58520c4c 100644
--- a/Source/Core/Controls/ImageSelectorControl.cs
+++ b/Source/Core/Controls/ImageSelectorControl.cs
@@ -35,10 +35,10 @@ namespace CodeImp.DoomBuilder.Controls
 		public event EventHandler OnValueChanged; //mxd
 		
 		private Bitmap bmp;
-		//private bool ispressed;
 		private bool ismouseinside;
 		private MouseButtons button;
 		protected bool allowclear;
+		private string previousImageName; //mxd
 		
 		#endregion
 
@@ -180,10 +180,12 @@ namespace CodeImp.DoomBuilder.Controls
 				// Show it centered
 				General.DisplayZoomedImage(preview, image);
 				preview.Refresh();
+			}
 
-				//mxd. Dispatch event
-				if(OnValueChanged != null)
-					OnValueChanged(this, EventArgs.Empty);
+			//mxd. Dispatch event
+			if(OnValueChanged != null && previousImageName != name.Text) {
+				previousImageName = name.Text;
+				OnValueChanged(this, EventArgs.Empty);
 			}
 		}
 
diff --git a/Source/Core/Controls/LinedefInfoPanel.Designer.cs b/Source/Core/Controls/LinedefInfoPanel.Designer.cs
index dedd0ecf2..34ce5ad11 100644
--- a/Source/Core/Controls/LinedefInfoPanel.Designer.cs
+++ b/Source/Core/Controls/LinedefInfoPanel.Designer.cs
@@ -144,39 +144,39 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label1
 			// 
-			label1.AutoSize = true;
-			label1.Location = new System.Drawing.Point(11, 19);
+			label1.Location = new System.Drawing.Point(8, 19);
 			label1.Name = "label1";
-			label1.Size = new System.Drawing.Size(41, 14);
+			label1.Size = new System.Drawing.Size(44, 14);
 			label1.TabIndex = 0;
 			label1.Text = "Action:";
+			label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
 			// 
 			// label4
 			// 
-			label4.AutoSize = true;
-			label4.Location = new System.Drawing.Point(24, 77);
+			label4.Location = new System.Drawing.Point(8, 77);
 			label4.Name = "label4";
-			label4.Size = new System.Drawing.Size(27, 14);
+			label4.Size = new System.Drawing.Size(44, 14);
 			label4.TabIndex = 4;
 			label4.Text = "Tag:";
+			label4.TextAlign = System.Drawing.ContentAlignment.TopRight;
 			// 
 			// label3
 			// 
-			label3.AutoSize = true;
-			label3.Location = new System.Drawing.Point(14, 58);
+			label3.Location = new System.Drawing.Point(8, 58);
 			label3.Name = "label3";
-			label3.Size = new System.Drawing.Size(38, 14);
+			label3.Size = new System.Drawing.Size(44, 14);
 			label3.TabIndex = 3;
 			label3.Text = "Angle:";
+			label3.TextAlign = System.Drawing.ContentAlignment.TopRight;
 			// 
 			// label2
 			// 
-			label2.AutoSize = true;
-			label2.Location = new System.Drawing.Point(9, 39);
+			label2.Location = new System.Drawing.Point(8, 39);
 			label2.Name = "label2";
-			label2.Size = new System.Drawing.Size(43, 14);
+			label2.Size = new System.Drawing.Size(44, 14);
 			label2.TabIndex = 2;
 			label2.Text = "Length:";
+			label2.TextAlign = System.Drawing.ContentAlignment.TopRight;
 			// 
 			// infopanel
 			// 
diff --git a/Source/Core/Controls/LinedefInfoPanel.resx b/Source/Core/Controls/LinedefInfoPanel.resx
index 27dc0cde9..055a3ee17 100644
--- a/Source/Core/Controls/LinedefInfoPanel.resx
+++ b/Source/Core/Controls/LinedefInfoPanel.resx
@@ -117,27 +117,15 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-  <metadata name="label1.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>True</value>
-  </metadata>
   <metadata name="label1.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>False</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="label4.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>False</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="label3.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>False</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="label2.GenerateMember" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>False</value>
   </metadata>
@@ -201,6 +189,12 @@
   <metadata name="frontsector.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
+  <metadata name="frontsector.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
+  <metadata name="backsector.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+    <value>True</value>
+  </metadata>
   <metadata name="backsector.Locked" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>True</value>
   </metadata>
diff --git a/Source/Core/Controls/SectorInfoPanel.Designer.cs b/Source/Core/Controls/SectorInfoPanel.Designer.cs
index ca8b87604..fdc2dacfb 100644
--- a/Source/Core/Controls/SectorInfoPanel.Designer.cs
+++ b/Source/Core/Controls/SectorInfoPanel.Designer.cs
@@ -86,7 +86,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label13
 			// 
-			label13.Location = new System.Drawing.Point(103, 75);
+			label13.Location = new System.Drawing.Point(103, 77);
 			label13.Name = "label13";
 			label13.Size = new System.Drawing.Size(70, 14);
 			label13.TabIndex = 14;
@@ -95,7 +95,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label5
 			// 
-			label5.Location = new System.Drawing.Point(103, 55);
+			label5.Location = new System.Drawing.Point(103, 58);
 			label5.Name = "label5";
 			label5.Size = new System.Drawing.Size(70, 14);
 			label5.TabIndex = 8;
@@ -104,7 +104,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label4
 			// 
-			label4.Location = new System.Drawing.Point(8, 75);
+			label4.Location = new System.Drawing.Point(8, 77);
 			label4.Name = "label4";
 			label4.Size = new System.Drawing.Size(44, 14);
 			label4.TabIndex = 4;
@@ -113,7 +113,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label3
 			// 
-			label3.Location = new System.Drawing.Point(8, 55);
+			label3.Location = new System.Drawing.Point(8, 58);
 			label3.Name = "label3";
 			label3.Size = new System.Drawing.Size(44, 14);
 			label3.TabIndex = 3;
@@ -122,7 +122,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label2
 			// 
-			label2.Location = new System.Drawing.Point(8, 35);
+			label2.Location = new System.Drawing.Point(8, 39);
 			label2.Name = "label2";
 			label2.Size = new System.Drawing.Size(44, 14);
 			label2.TabIndex = 2;
@@ -131,12 +131,12 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// label1
 			// 
-			label1.AutoSize = true;
-			label1.Location = new System.Drawing.Point(13, 15);
+			label1.Location = new System.Drawing.Point(8, 19);
 			label1.Name = "label1";
-			label1.Size = new System.Drawing.Size(39, 14);
+			label1.Size = new System.Drawing.Size(44, 14);
 			label1.TabIndex = 0;
 			label1.Text = "Effect:";
+			label1.TextAlign = System.Drawing.ContentAlignment.TopRight;
 			// 
 			// ceilingLightLabel
 			// 
@@ -234,7 +234,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// brightness
 			// 
-			this.brightness.Location = new System.Drawing.Point(177, 75);
+			this.brightness.Location = new System.Drawing.Point(177, 77);
 			this.brightness.Name = "brightness";
 			this.brightness.Size = new System.Drawing.Size(38, 14);
 			this.brightness.TabIndex = 17;
@@ -242,7 +242,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// height
 			// 
-			this.height.Location = new System.Drawing.Point(177, 55);
+			this.height.Location = new System.Drawing.Point(177, 58);
 			this.height.Name = "height";
 			this.height.Size = new System.Drawing.Size(38, 14);
 			this.height.TabIndex = 11;
@@ -250,7 +250,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// tag
 			// 
-			this.tag.Location = new System.Drawing.Point(55, 75);
+			this.tag.Location = new System.Drawing.Point(55, 77);
 			this.tag.Name = "tag";
 			this.tag.Size = new System.Drawing.Size(42, 14);
 			this.tag.TabIndex = 7;
@@ -258,7 +258,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// floor
 			// 
-			this.floor.Location = new System.Drawing.Point(55, 55);
+			this.floor.Location = new System.Drawing.Point(55, 58);
 			this.floor.Name = "floor";
 			this.floor.Size = new System.Drawing.Size(42, 14);
 			this.floor.TabIndex = 6;
@@ -266,7 +266,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// 
 			// ceiling
 			// 
-			this.ceiling.Location = new System.Drawing.Point(55, 35);
+			this.ceiling.Location = new System.Drawing.Point(55, 39);
 			this.ceiling.Name = "ceiling";
 			this.ceiling.Size = new System.Drawing.Size(42, 14);
 			this.ceiling.TabIndex = 5;
@@ -275,7 +275,7 @@ namespace CodeImp.DoomBuilder.Controls
 			// effect
 			// 
 			this.effect.AutoSize = true;
-			this.effect.Location = new System.Drawing.Point(55, 15);
+			this.effect.Location = new System.Drawing.Point(55, 19);
 			this.effect.Name = "effect";
 			this.effect.Size = new System.Drawing.Size(123, 14);
 			this.effect.TabIndex = 1;
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index ab5f9737c..de9f3233d 100644
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -56,6 +56,7 @@ namespace CodeImp.DoomBuilder.Windows
 		
 		// Status bar
 		private const string STATUS_READY_TEXT = "Ready.";
+		private const string STATUS_NO_SELECTION_TEXT = "Nothing selected."; //mxd
 		private const string STATUS_LOADING_TEXT = "Loading resources...";
 		private const int WARNING_FLASH_COUNT = 10;
 		private const int WARNING_FLASH_INTERVAL = 100;
@@ -153,6 +154,7 @@ namespace CodeImp.DoomBuilder.Windows
 		private StatusInfo status;
 		private int statusflashcount;
 		private bool statusflashicon;
+		private string selectionInfo = STATUS_NO_SELECTION_TEXT; //mxd
 		
 		// Properties
 		private IntPtr windowptr;
@@ -681,12 +683,21 @@ namespace CodeImp.DoomBuilder.Windows
 				// When no particular information is to be displayed.
 				// The messages displayed depends on running background processes.
 				case StatusType.Ready:
-					if((General.Map != null) && (General.Map.Data != null) && General.Map.Data.IsLoading)
-						newstatus.message = STATUS_LOADING_TEXT;
+					if((General.Map != null) && (General.Map.Data != null))
+						if(General.Map.Data.IsLoading)
+							newstatus.message = STATUS_LOADING_TEXT;
+						else
+							newstatus.message = selectionInfo; //mxd
 					else
 						newstatus.message = STATUS_READY_TEXT;
 					break;
 
+				case StatusType.Selection: //mxd
+					if(string.IsNullOrEmpty(newstatus.message))
+						newstatus.message = STATUS_NO_SELECTION_TEXT;
+					selectionInfo = newstatus.message;
+					break;
+
 				// Shows information without flashing the icon.
 				case StatusType.Info:
 					if(!newstatus.displayed)
@@ -759,6 +770,7 @@ namespace CodeImp.DoomBuilder.Windows
 				case StatusType.Ready:
 				case StatusType.Info:
 				case StatusType.Action:
+				case StatusType.Selection: //mxd
 					statuslabel.Image = STATUS_IMAGES[statusflashindex, statusicon];
 					break;
 				
@@ -3001,6 +3013,7 @@ namespace CodeImp.DoomBuilder.Windows
 			}else{
 				SectorEditForm f = new SectorEditForm();
 				f.Setup(sectors);
+				f.OnValuesChanged += new EventHandler(EditForm_OnValuesChanged);
 				result = f.ShowDialog(this);
 				f.Dispose();
 			}
diff --git a/Source/Core/Windows/SectorEditForm.Designer.cs b/Source/Core/Windows/SectorEditForm.Designer.cs
index ca2b2732c..70bf2d6fc 100644
--- a/Source/Core/Windows/SectorEditForm.Designer.cs
+++ b/Source/Core/Windows/SectorEditForm.Designer.cs
@@ -178,11 +178,13 @@ namespace CodeImp.DoomBuilder.Windows
 			this.brightness.AllowNegative = false;
 			this.brightness.AllowRelative = true;
 			this.brightness.ButtonStep = 8;
+			this.brightness.ButtonStepFloat = 1F;
 			this.brightness.Location = new System.Drawing.Point(99, 124);
 			this.brightness.Name = "brightness";
 			this.brightness.Size = new System.Drawing.Size(73, 24);
 			this.brightness.StepValues = null;
 			this.brightness.TabIndex = 24;
+			this.brightness.WhenTextChanged += new System.EventHandler(this.brightness_WhenTextChanged);
 			// 
 			// ceilingheight
 			// 
@@ -190,6 +192,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.ceilingheight.AllowNegative = true;
 			this.ceilingheight.AllowRelative = true;
 			this.ceilingheight.ButtonStep = 8;
+			this.ceilingheight.ButtonStepFloat = 1F;
 			this.ceilingheight.Location = new System.Drawing.Point(99, 35);
 			this.ceilingheight.Name = "ceilingheight";
 			this.ceilingheight.Size = new System.Drawing.Size(88, 24);
@@ -258,6 +261,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.floortex.Size = new System.Drawing.Size(83, 105);
 			this.floortex.TabIndex = 2;
 			this.floortex.TextureName = "";
+			this.floortex.OnValueChanged += new System.EventHandler(this.floortex_OnValueChanged);
 			// 
 			// floorheight
 			// 
@@ -265,6 +269,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.floorheight.AllowNegative = true;
 			this.floorheight.AllowRelative = true;
 			this.floorheight.ButtonStep = 8;
+			this.floorheight.ButtonStepFloat = 1F;
 			this.floorheight.Location = new System.Drawing.Point(99, 65);
 			this.floorheight.Name = "floorheight";
 			this.floorheight.Size = new System.Drawing.Size(88, 24);
@@ -279,6 +284,7 @@ namespace CodeImp.DoomBuilder.Windows
 			this.ceilingtex.Size = new System.Drawing.Size(83, 105);
 			this.ceilingtex.TabIndex = 3;
 			this.ceilingtex.TextureName = "";
+			this.ceilingtex.OnValueChanged += new System.EventHandler(this.ceilingtex_OnValueChanged);
 			// 
 			// cancel
 			// 
diff --git a/Source/Core/Windows/SectorEditForm.cs b/Source/Core/Windows/SectorEditForm.cs
index aedb02975..1ae32ac4f 100644
--- a/Source/Core/Windows/SectorEditForm.cs
+++ b/Source/Core/Windows/SectorEditForm.cs
@@ -26,10 +26,50 @@ using CodeImp.DoomBuilder.Types;
 
 namespace CodeImp.DoomBuilder.Windows
 {
-	internal partial class SectorEditForm : DelayedForm
+	public partial class SectorEditForm : DelayedForm
 	{
-		// Variables
+		#region ================== Events
+
+		public event EventHandler OnValuesChanged; //mxd
+
+		#endregion
+
+		#region ================== Variables
+
 		private ICollection<Sector> sectors;
+		private List<SectorProperties> sectorProps;
+		private bool blockUpdate; //mxd
+
+		private struct SectorProperties //mxd
+		{
+			//public int Tag;
+			//public int Effect;
+			public int Brightness;
+			public int FloorHeight;
+			public int CeilHeight;
+			public string FloorTexture;
+			public string CeilTexture;
+
+			public SectorProperties(Sector s) {
+				//Tag = s.Tag;
+				//Effect = s.Effect;
+				Brightness = s.Brightness;
+				FloorHeight = s.FloorHeight;
+				CeilHeight = s.CeilHeight;
+				FloorTexture = s.FloorTexture;
+				CeilTexture = s.CeilTexture;
+			}
+		}
+
+		#endregion
+
+		#region ================== Properties
+
+		public ICollection<Sector> Selection { get { return sectors; } } //mxd
+
+		#endregion
+
+		#region ================== Constructor
 
 		// Constructor
 		public SectorEditForm()
@@ -47,15 +87,22 @@ namespace CodeImp.DoomBuilder.Windows
 			// Set steps for brightness field
 			brightness.StepValues = General.Map.Config.BrightnessLevels;
 		}
-		
+
+		#endregion
+
+		#region ================== Methods
+
 		// This sets up the form to edit the given sectors
 		public void Setup(ICollection<Sector> sectors)
 		{
+			blockUpdate = true;
+			
 			Sector sc;
 			
 			// Keep this list
 			this.sectors = sectors;
 			if(sectors.Count > 1) this.Text = "Edit Sectors (" + sectors.Count + ")";
+			sectorProps = new List<SectorProperties>();
 
 			////////////////////////////////////////////////////////////////////////
 			// Set all options to the first sector properties
@@ -97,10 +144,20 @@ namespace CodeImp.DoomBuilder.Windows
 
 				// Action
 				if(s.Tag != sc.Tag)	tagSelector.ClearTag(); //mxd
+
+				//mxd. Store initial properties
+				sectorProps.Add(new SectorProperties(s));
 			}
 
 			// Show sector height
 			UpdateSectorHeight();
+
+			//mxd. Make undo
+			string undodesc = "sector";
+			if(sectors.Count > 1) undodesc = sectors.Count + " sectors";
+			General.Map.UndoRedo.CreateUndo("Edit " + undodesc);
+
+			blockUpdate = false;
 		}
 
 		// This updates the sector height field
@@ -148,50 +205,36 @@ namespace CodeImp.DoomBuilder.Windows
 			}
 		}
 
+		#endregion
+
+		#region ================== Events
+
 		// OK clicked
 		private void apply_Click(object sender, EventArgs e)
 		{
-			string undodesc = "sector";
-			
+			//mxd. Apply "Static" properties
 			// Verify the tag
 			tagSelector.ValidateTag(); //mxd
-			if((tagSelector.GetTag(0) < General.Map.FormatInterface.MinTag) || (tagSelector.GetTag(0) > General.Map.FormatInterface.MaxTag))
-			{
+			if((tagSelector.GetTag(0) < General.Map.FormatInterface.MinTag) || (tagSelector.GetTag(0) > General.Map.FormatInterface.MaxTag)) {
 				General.ShowWarningMessage("Sector tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK);
 				return;
 			}
 
 			// Verify the effect
-			if((effect.Value < General.Map.FormatInterface.MinEffect) || (effect.Value > General.Map.FormatInterface.MaxEffect))
-			{
+			if((effect.Value < General.Map.FormatInterface.MinEffect) || (effect.Value > General.Map.FormatInterface.MaxEffect)) {
 				General.ShowWarningMessage("Sector effect must be between " + General.Map.FormatInterface.MinEffect + " and " + General.Map.FormatInterface.MaxEffect + ".", MessageBoxButtons.OK);
 				return;
 			}
-			
-			// Make undo
-			if(sectors.Count > 1) undodesc = sectors.Count + " sectors";
-			General.Map.UndoRedo.CreateUndo("Edit " + undodesc);
 
 			// Go for all sectors
-			foreach(Sector s in sectors)
-			{
+			foreach(Sector s in sectors) {
 				// Effects
 				if(!effect.Empty) s.Effect = effect.Value;
-				s.Brightness = General.Clamp(brightness.GetResult(s.Brightness), General.Map.FormatInterface.MinBrightness, General.Map.FormatInterface.MaxBrightness);
-
-				// Floor/Ceiling
-				s.FloorHeight = floorheight.GetResult(s.FloorHeight);
-				s.CeilHeight = ceilingheight.GetResult(s.CeilHeight);
-				s.SetFloorTexture(floortex.GetResult(s.FloorTexture));
-				s.SetCeilTexture(ceilingtex.GetResult(s.CeilTexture));
 
 				// Action
 				s.Tag = tagSelector.GetTag(s.Tag); //mxd
 			}
-			
-			// Update the used textures
-			General.Map.Data.UpdateUsedTextures();
-			
+
 			// Done
 			General.Map.IsChanged = true;
 			this.DialogResult = DialogResult.OK;
@@ -201,7 +244,10 @@ namespace CodeImp.DoomBuilder.Windows
 		// Cancel clicked
 		private void cancel_Click(object sender, EventArgs e)
 		{
-			// Be gone
+			//mxd. perform undo
+			General.Map.UndoRedo.PerformUndo();
+			
+			// And be gone
 			this.DialogResult = DialogResult.Cancel;
 			this.Close();
 		}
@@ -213,23 +259,125 @@ namespace CodeImp.DoomBuilder.Windows
 			effect.Value = EffectBrowserForm.BrowseEffect(this, effect.Value);
 		}
 
+		// Help
+		private void SectorEditForm_HelpRequested(object sender, HelpEventArgs hlpevent) {
+			General.ShowHelp("w_sectoredit.html");
+			hlpevent.Handled = true;
+		}
+
+		#endregion
+
+		#region ================== mxd. Control Events
+
 		// Ceiling height changes
 		private void ceilingheight_TextChanged(object sender, EventArgs e)
 		{
 			UpdateSectorHeight();
+
+			if(blockUpdate) return;
+
+			//restore values
+			if(string.IsNullOrEmpty(ceilingheight.Text)) {
+				int i = 0;
+
+				foreach(Sector s in sectors)
+					s.CeilHeight = sectorProps[i++].CeilHeight;
+			//update values
+			} else {
+				foreach(Sector s in sectors) 
+					s.CeilHeight = ceilingheight.GetResult(s.CeilHeight);
+			}
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
 
 		// Floor height changes
 		private void floorheight_TextChanged(object sender, EventArgs e)
 		{
 			UpdateSectorHeight();
+
+			if(blockUpdate) return;
+
+			//restore values
+			if(string.IsNullOrEmpty(floorheight.Text)) {
+				int i = 0;
+
+				foreach(Sector s in sectors)
+					s.FloorHeight = sectorProps[i++].FloorHeight;
+			//update values
+			} else {
+				foreach(Sector s in sectors)
+					s.FloorHeight = floorheight.GetResult(s.FloorHeight);
+			}
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
 
-		// Help
-		private void SectorEditForm_HelpRequested(object sender, HelpEventArgs hlpevent)
-		{
-			General.ShowHelp("w_sectoredit.html");
-			hlpevent.Handled = true;
+		private void floortex_OnValueChanged(object sender, EventArgs e) {
+			if(blockUpdate) return;
+
+			//restore values
+			if(string.IsNullOrEmpty(floortex.TextureName)) {
+				int i = 0;
+
+				foreach(Sector s in sectors)
+					s.SetFloorTexture(sectorProps[i++].FloorTexture);
+			//update values
+			} else {
+				foreach(Sector s in sectors)
+					s.SetFloorTexture(floortex.GetResult(s.FloorTexture));
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		private void ceilingtex_OnValueChanged(object sender, EventArgs e) {
+			if(blockUpdate) return;
+
+			//restore values
+			if(string.IsNullOrEmpty(ceilingtex.TextureName)) {
+				int i = 0;
+
+				foreach(Sector s in sectors)
+					s.SetCeilTexture(sectorProps[i++].CeilTexture);
+			//update values
+			} else {
+				foreach(Sector s in sectors)
+					s.SetCeilTexture(ceilingtex.GetResult(s.CeilTexture));
+			}
+
+			// Update the used textures
+			General.Map.Data.UpdateUsedTextures();
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
 		}
+
+		private void brightness_WhenTextChanged(object sender, EventArgs e) {
+			if(blockUpdate) return;
+
+			//restore values
+			if(string.IsNullOrEmpty(brightness.Text)) {
+				int i = 0;
+
+				foreach(Sector s in sectors)
+					s.Brightness = sectorProps[i++].Brightness;
+			//update values
+			} else {
+				foreach(Sector s in sectors)
+					s.Brightness = General.Clamp(brightness.GetResult(s.Brightness), General.Map.FormatInterface.MinBrightness, General.Map.FormatInterface.MaxBrightness);
+			}
+
+			General.Map.IsChanged = true;
+			if(OnValuesChanged != null) OnValuesChanged(this, EventArgs.Empty);
+		}
+
+		#endregion
 	}
 }
\ No newline at end of file
diff --git a/Source/Core/Windows/StatusInfo.cs b/Source/Core/Windows/StatusInfo.cs
index 0407b13f3..776edfa69 100644
--- a/Source/Core/Windows/StatusInfo.cs
+++ b/Source/Core/Windows/StatusInfo.cs
@@ -40,6 +40,11 @@ namespace CodeImp.DoomBuilder.Windows
 		/// When no particular information is to be displayed. The messages displayed depends on running background processes.
 		/// </summary>
 		Ready,
+
+		/// <summary>
+		/// mxd. Displays information about current selection.
+		/// </summary>
+		Selection,
 		
 		/// <summary>
 		/// Shows action information and flashes up the status icon once.
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
index 7c4d9528b..2221a3d2a 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
@@ -141,6 +141,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			else
 				marqueSelectionMode = MarqueSelectionMode.SELECT;
 		}
+
+		//mxd
+		public override void OnUndoEnd() {
+			base.OnUndoEnd();
+			updateSelectionInfo();
+		}
+
+		//mxd
+		public override void OnRedoEnd() {
+			base.OnRedoEnd();
+			updateSelectionInfo();
+		}
+
+		//mxd
+		protected virtual void updateSelectionInfo() {
+			General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+		}
 		
 		#endregion
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index d22c796ec..bf631c8f8 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -275,6 +275,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// Convert geometry selection to linedefs selection
 			General.Map.Map.ConvertSelection(SelectionType.Linedefs);
+			updateSelectionInfo(); //mxd
 		}
 		
 		// Mode disengages
@@ -398,6 +399,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					General.Map.Map.ClearSelectedLinedefs();
 					General.Interface.RedrawDisplay();
 				}
+
+				//mxd
+				updateSelectionInfo();
 			}
 
 			base.OnSelectEnd();
@@ -473,6 +477,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						General.Interface.RedrawDisplay();
 					}
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			editpressed = false;
@@ -510,6 +516,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							l.Selected = !l.Selected;
 						highlighted = l;
 
+						updateSelectionInfo(); //mxd
+
 						// Update entire display
 						General.Interface.RedrawDisplay();
 					}
@@ -654,6 +662,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						}
 					}
 				}
+
+				//mxd
+				updateSelectionInfo();
 			}
 			
 			base.OnEndMultiSelection();
@@ -692,6 +703,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return base.OnCopyBegin();
 		}
 
+		//mxd
+		protected override void updateSelectionInfo() {
+			if(General.Map.Map.SelectedLinedefsCount > 0)
+				General.Interface.DisplayStatus(StatusType.Selection, General.Map.Map.SelectedLinedefsCount + (General.Map.Map.SelectedLinedefsCount == 1 ? " linedef" : " linedefs") + " selected.");
+			else
+				General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+		}
+
 		#endregion
 
 		#region ================== Actions
@@ -796,6 +815,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Clear selection
 			General.Map.Map.ClearAllSelected();
 
+			//mxd
+			General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+
 			// Redraw
 			General.Interface.RedrawDisplay();
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index 8d8e47803..100f6a733 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -417,6 +417,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// Convert geometry selection to sectors only
 			General.Map.Map.ConvertSelection(SelectionType.Sectors);
+			updateSelectionInfo(); //mxd
 
 			// Make text labels for sectors
 			SetupLabels();
@@ -558,6 +559,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					General.Map.Map.ClearSelectedSectors();
 					General.Interface.RedrawDisplay();
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			base.OnSelectEnd();
@@ -620,9 +623,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					if(General.Interface.IsActiveWindow)
 					{
-						// Show sector edit dialog
+						//mxd. Show realtime vertex edit dialog
+						General.Interface.OnEditFormValuesChanged += new EventHandler(sectorEditForm_OnValuesChanged);
 						General.Interface.ShowEditSectors(selected);
-						General.Map.Map.Update();
 						
 						// When a single sector was selected, deselect it now
 						if(selected.Count == 1)
@@ -630,17 +633,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							General.Map.Map.ClearSelectedSectors();
 							General.Map.Map.ClearSelectedLinedefs();
 						}
-
-						// Update entire display
-						General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
-						General.Interface.RedrawDisplay();
 					}
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			editpressed = false;
 			base.OnEditEnd();
 		}
+
+		//mxd
+		private void sectorEditForm_OnValuesChanged(object sender, EventArgs e) {
+			// Update entire display
+			General.Map.Map.Update();
+			General.Map.Renderer2D.Update3dFloorTagsList();
+			General.Interface.RedrawDisplay();
+		}
 		
 		// Mouse moves
 		public override void OnMouseMove(MouseEventArgs e)
@@ -697,6 +706,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						// Update entire display
 						General.Interface.RedrawDisplay();
 					}
+
+					updateSelectionInfo(); //mxd
 				}
 			} 
 			else if(e.Button == MouseButtons.None) // Not holding any buttons?
@@ -975,6 +986,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Make sure all linedefs reflect selected sectors
 				foreach(Sidedef sd in General.Map.Map.Sidedefs)
 					sd.Line.Selected = sd.Sector.Selected || (sd.Other != null && sd.Other.Sector.Selected);
+
+				updateSelectionInfo(); //mxd
 			}
 			
 			base.OnEndMultiSelection();
@@ -1040,6 +1053,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Clear labels
 			SetupLabels();
 		}
+
+		//mxd
+		protected override void updateSelectionInfo() {
+			if(General.Map.Map.SelectedSectorsCount > 0)
+				General.Interface.DisplayStatus(StatusType.Selection, General.Map.Map.SelectedSectorsCount + (General.Map.Map.SelectedSectorsCount == 1 ? " sector" : " sectors") + " selected.");
+			else
+				General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+		}
 		
 		#endregion
 
@@ -1644,6 +1665,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Clear selection
 			General.Map.Map.ClearAllSelected();
 
+			General.Interface.DisplayStatus(StatusType.Selection, string.Empty); //mxd
+
 			// Clear labels
 			foreach(TextLabel[] labelarray in labels.Values)
 				foreach(TextLabel l in labelarray) l.Text = "";
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index 249a41f14..23df1a97f 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -103,6 +103,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Convert geometry selection to linedefs selection
 			General.Map.Map.ConvertSelection(SelectionType.Linedefs);
 			General.Map.Map.SelectionType = SelectionType.Things;
+			updateSelectionInfo(); //mxd
 		}
 
 		// Mode disengages
@@ -326,6 +327,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					General.Map.Map.ClearSelectedThings();
 					General.Interface.RedrawDisplay();
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			base.OnSelectEnd();
@@ -419,6 +422,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						}
 					}
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			editpressed = false;
@@ -456,6 +461,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							t.Selected = !t.Selected;
 						highlighted = t;
 
+						updateSelectionInfo(); //mxd
+
 						// Update entire display
 						General.Interface.RedrawDisplay();
 					}
@@ -571,6 +578,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					foreach(Thing t in General.Map.ThingsFilter.VisibleThings)
 						if(!selectionrect.Contains(t.Position.x, t.Position.y)) t.Selected = false;
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 			
 			base.OnEndMultiSelection();
@@ -609,6 +618,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return base.OnCopyBegin();
 		}
 
+		//mxd
+		protected override void updateSelectionInfo() {
+			if(General.Map.Map.SelectedThingsCount > 0)
+				General.Interface.DisplayStatus(StatusType.Selection, General.Map.Map.SelectedThingsCount + (General.Map.Map.SelectedThingsCount == 1 ? " thing" : " things") + " selected.");
+			else
+				General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+		}
+
 		#endregion
 
 		#region ================== Actions
diff --git a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
index 67df9486e..9528d15a2 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
@@ -95,6 +95,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// Convert geometry selection to vertices only
 			General.Map.Map.ConvertSelection(SelectionType.Vertices);
+			updateSelectionInfo(); //mxd
 		}
 
 		// Mode disengages
@@ -212,7 +213,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				// Render highlighted item
 				if((highlightedLine != null) && !highlightedLine.IsDisposed) {
-					renderer.PlotLinedef(highlightedLine, General.Colors.InfoLine);
+					renderer.PlotLinedef(highlightedLine, General.Colors.InfoLine.WithAlpha(128));
 
 					if(highlighted != null && !highlighted.IsDisposed) {
 						renderer.PlotVertex(highlightedLine.Start, highlightedLine.Start == highlighted ? ColorCollection.HIGHLIGHT : renderer.DetermineVertexColor(highlightedLine.Start));
@@ -271,6 +272,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					General.Map.Map.ClearSelectedVertices();
 					General.Interface.RedrawDisplay();
 				}
+
+				//mxd
+				updateSelectionInfo();
 			}
 
 			base.OnSelectEnd();
@@ -295,6 +299,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					General.Map.Map.ClearSelectedVertices();
 					highlighted.Selected = true;
 					General.Interface.RedrawDisplay();
+
+					//mxd
+					General.Interface.DisplayStatus(StatusType.Selection, "1 vertex selected.");
 				}
 
 				// Update display
@@ -405,6 +412,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if(selected.Count == 1) General.Map.Map.ClearSelectedVertices();
 					}
 				}
+
+				updateSelectionInfo(); //mxd
 			}
 
 			editpressed = false;
@@ -450,6 +459,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							v.Selected = !v.Selected;
 						highlighted = v;
 
+						updateSelectionInfo(); //mxd
+
 						// Update entire display
 						General.Interface.RedrawDisplay();
 					}
@@ -571,6 +582,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					foreach(Vertex v in General.Map.Map.Vertices)
 						if(!selectionrect.Contains(v.Position.x, v.Position.y)) v.Selected = false;
 				}
+
+				//mxd
+				updateSelectionInfo();
 			}
 			
 			base.OnEndMultiSelection();
@@ -608,6 +622,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			return base.OnCopyBegin();
 		}
+
+		//mxd
+		protected override void updateSelectionInfo() {
+			if(General.Map.Map.SelectedVerticessCount > 0)
+				General.Interface.DisplayStatus(StatusType.Selection, General.Map.Map.SelectedVerticessCount + (General.Map.Map.SelectedVerticessCount == 1 ? " vertex" : " vertices") + " selected.");
+			else
+				General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+		}
 		
 		#endregion
 
@@ -676,6 +698,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Clear selection
 			General.Map.Map.ClearAllSelected();
 
+			//mxd
+			General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
+
 			// Redraw
 			General.Interface.RedrawDisplay();
 		}
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
index 565674056..f4fadc7bc 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
@@ -28,6 +28,7 @@ using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.VisualModes;
 using CodeImp.DoomBuilder.Types;
 using CodeImp.DoomBuilder.GZBuilder.Tools;
+using CodeImp.DoomBuilder.Windows;
 
 #endregion
 
@@ -642,19 +643,23 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(General.Interface.IsActiveWindow)
 			{
+				//mxd
 				List<Sector> sectors = mode.GetSelectedSectors();
-				DialogResult result = General.Interface.ShowEditSectors(sectors);
-				if(result == DialogResult.OK)
-				{
-					// Rebuild sector
-					foreach(Sector s in sectors)
-					{
-						if(mode.VisualSectorExists(s))
-						{
-							BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s);
-							vs.UpdateSectorGeometry(true);
-						}
-					}
+				General.Interface.OnEditFormValuesChanged += new System.EventHandler(Interface_OnEditFormValuesChanged);
+				General.Interface.ShowEditSectors(sectors);
+			}
+		}
+
+		//mxd
+		private void Interface_OnEditFormValuesChanged(object sender, System.EventArgs e) {
+			SectorEditForm form = sender as SectorEditForm;
+			if(form == null) return;
+
+			// Update what must be updated
+			foreach(Sector s in form.Selection) {
+				if(mode.VisualSectorExists(s)) {
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s);
+					vs.UpdateSectorGeometry(true);
 				}
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index 0fccdd3f7..114b00768 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -648,6 +648,42 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				vs.Sides[side].lower.SelectNeighbours(select, withSameTexture, withSameHeight);
 			}
 		}
+
+		//mxd
+		private void updateSelectionInfo() {
+			int numWalls = 0;
+			int numFloors = 0;
+			int numCeilings = 0;
+			int numThings = 0;
+			int numVerts = 0;
+
+			foreach(IVisualEventReceiver obj in selectedobjects) {
+				if(!obj.IsSelected()) continue;
+
+				if(obj is BaseVisualThing) numThings++;
+				else if(obj is BaseVisualVertex) numVerts++;
+				else if(obj is VisualCeiling) numCeilings++;
+				else if(obj is VisualFloor)	numFloors++;
+				else if(obj is VisualMiddleSingle || obj is VisualMiddleDouble || obj is VisualLower || obj is VisualUpper || obj is VisualMiddle3D || obj is VisualMiddleBack)
+					numWalls++;
+			}
+
+			string result = "";
+
+			if(numWalls > 0)    result = numWalls + (numWalls > 1 ? " sidedefs" : " sidedef");
+			if(numFloors > 0)   result += (result.Length > 0 ? ", " : "") + numFloors + (numFloors > 1 ? " floors" : " floor");
+			if(numCeilings > 0)	result += (result.Length > 0 ? ", " : "") + numCeilings + (numCeilings > 1 ? " ceilings" : " ceiling");
+			if(numThings > 0)	result += (result.Length > 0 ? ", " : "") + numThings + (numThings > 1 ? " things" : " thing");
+			if(numVerts > 0)	result += (result.Length > 0 ? ", " : "") + numVerts + (numVerts > 1 ? " vertices" : " vertex");
+
+			if(!string.IsNullOrEmpty(result)) {
+				int pos = result.LastIndexOf(",");
+				if(pos != -1) result = result.Remove(pos, 1).Insert(pos, " and");
+				result += " selected";
+			}
+
+			General.Interface.DisplayStatus(StatusType.Selection, result);
+		}
 		
 		#endregion
 
@@ -896,7 +932,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			//mxd
 			useSelectionFromClassicMode = BuilderPlug.Me.SyncSelection ? !General.Interface.ShiftState : General.Interface.ShiftState;
-			
+			if(useSelectionFromClassicMode)	updateSelectionInfo();
+
 			// Read settings
 			cameraflooroffset = General.Map.Config.ReadSetting("cameraflooroffset", cameraflooroffset);
 			cameraceilingoffset = General.Map.Config.ReadSetting("cameraceilingoffset", cameraceilingoffset);
@@ -1241,6 +1278,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			
 			// We can't group with this undo level anymore
 			lastundogroup = UndoGroup.None;
+
+			//mxd
+			updateSelectionInfo();
 		}
 		
 		// Redo performed
@@ -1259,6 +1299,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
             }
 
 			RebuildSelectedObjectsList();
+
+			//mxd
+			updateSelectionInfo();
 		}
 		
 		#endregion
@@ -1620,6 +1663,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					pair.Value.Deselect();
 				}
 			}
+
+			//mxd
+			General.Interface.DisplayStatus(StatusType.Selection, string.Empty);
 		}
 
 		[BeginAction("visualselect", BaseAction = true)]
@@ -1650,6 +1696,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			Renderer.ShowSelection = true;
 			Renderer.ShowHighlight = true;
 			PostAction();
+
+			//mxd
+			updateSelectionInfo();
 		}
 
 		[BeginAction("visualedit", BaseAction = true)]
@@ -1674,6 +1723,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		//mxd
 		private void Interface_OnEditFormValuesChanged(object sender, EventArgs e) {
+			if(allsectors == null) return;
+			
 			// Reset changed flags
 			foreach(KeyValuePair<Sector, VisualSector> vs in allsectors) {
 				BaseVisualSector bvs = (vs.Value as BaseVisualSector);
@@ -2163,7 +2214,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ScaleTextureUpX() {
 			PreAction(UndoGroup.TextureScaleChange);
 			List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
-			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0.25f, 0);
+			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(-0.1f, 0);
 			PostAction();
 		}
 
@@ -2172,7 +2223,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ScaleTextureDownX() {
 			PreAction(UndoGroup.TextureScaleChange);
 			List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
-			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(-0.25f, 0);
+			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0.1f, 0);
 			PostAction();
 		}
 
@@ -2181,7 +2232,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ScaleTextureUpY() {
 			PreAction(UndoGroup.TextureScaleChange);
 			List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
-			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0, 0.25f);
+			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0, 0.1f);
 			PostAction();
 		}
 
@@ -2190,7 +2241,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public void ScaleTextureDownY() {
 			PreAction(UndoGroup.TextureScaleChange);
 			List<IVisualEventReceiver> objs = GetSelectedObjects(true, true, false, false);
-			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0, -0.25f);
+			foreach(IVisualEventReceiver i in objs) i.OnChangeTextureScale(0, -0.1f);
 			PostAction();
 		}
 
-- 
GitLab