VOID_Core: Added a ResetGUI method that stops and starts all modules, to fix the problem with modules not drawing after a revert or ship load.
VOID_Core: Added a ResetGUI method that stops and starts all modules, to fix the problem with modules not drawing after a revert or ship load.

file:a/Tools.cs -> file:b/Tools.cs
--- a/Tools.cs
+++ b/Tools.cs
@@ -686,6 +686,136 @@
 			GUILayout.Label((dv2 * 1000).ToString("F2") + "m/s", GUILayout.ExpandWidth(false));
 			GUILayout.EndHorizontal();
 		}
+
+		// This implementation is adapted from FARGUIUtils.ClampToScreen
+		public static Rect ClampRectToScreen(Rect window, int xMargin, int yMargin)
+		{
+			window.x = Mathf.Clamp (window.x, xMargin - window.width, Screen.width - xMargin);
+			window.y = Mathf.Clamp (window.y, yMargin - window.height, Screen.height - yMargin);
+
+			return window;
+		}
+
+		public static Rect ClampRectToScreen(Rect window, int Margin)
+		{
+			return ClampRectToScreen(window, Margin, Margin);
+		}
+
+		public static Rect ClampRectToScreen(Rect window)
+		{
+			return ClampRectToScreen (window, 30);
+		}
+
+		public static Vector2 ClampV2ToScreen(Vector2 vec, uint xMargin, uint yMargin)
+		{
+			vec.x = Mathf.Clamp (vec.x, xMargin, Screen.width - xMargin);
+			vec.y = Mathf.Clamp (vec.y, yMargin, Screen.height - yMargin);
+
+			return vec;
+		}
+
+		public static Vector2 ClampV2ToScreen(Vector2 vec, uint Margin)
+		{
+			return ClampV2ToScreen(vec, Margin, Margin);
+		}
+
+		public static Vector2 ClampV2ToScreen(Vector2 vec)
+		{
+			return ClampV2ToScreen (vec, 15);
+		}
+
+		// UNDONE: This seems messy.  Can we clean it up?
+		public static Rect DockToWindow(Rect icon, Rect window)
+		{
+			// We can't set the x and y of the center point directly, so build a new vector.
+			Vector2 center = new Vector2 ();
+
+			// If we are near the top or bottom of the screen...
+			if (window.yMax > Screen.height - icon.height ||
+			    window.yMin < icon.height
+			    )
+			{
+				// If we are in a corner...
+				if (window.xMax > Screen.width - icon.width ||
+				    window.xMin < icon.width
+				    )
+				{
+					// If it is a top corner, put the icon below the window.
+					if (window.yMax < Screen.height / 2)
+					{
+						center.y = window.yMax + icon.height / 2;
+					}
+					// If it is a bottom corner, put the icon above the window.
+					else
+					{
+						center.y = window.yMin - icon.height / 2;
+					}
+				}
+				// If we are not in a corner...
+				else
+				{
+					// If we are along the top edge, align the icon's top edge with the top edge of the window
+					if (window.yMax > Screen.height / 2)
+					{
+						center.y = window.yMax - icon.height / 2;
+					}
+					// If we are along the bottom edge, align the icon's bottom edge with the bottom edge of the window
+					else
+					{
+						center.y = window.yMin + icon.height / 2;
+					}
+				}
+
+				// At the top or bottom, if we are towards the right, put the icon to the right of the window
+				if (window.center.x < Screen.width / 2)
+				{
+					center.x = window.xMin - icon.width / 2;
+				}
+				// At the top or bottom, if we are towards the left, put the icon to the left of the window
+				else
+				{
+					center.x = window.xMax + icon.width / 2;
+				}
+
+			}
+			// If we are not along the top or bottom of the screen...
+			else
+			{
+				// By default, center the icon above the window
+				center.y = window.yMin - icon.height / 2;
+				center.x = window.center.x;
+
+				// If we are along a side...
+				if (window.xMax > Screen.width - icon.width ||
+				    window.xMin < icon.width
+				    )
+				{
+					// UNDONE: I'm not sure I like the feel of this part.
+					// If we are along a side towards the bottom, put the icon below the window
+					if (window.center.y > Screen.height / 2)
+					{
+						center.y = window.yMax + icon.height / 2;
+					}
+
+					// Along the left side, align the left edge of the icon with the left edge of the window.
+					if (window.xMax > Screen.width - icon.width)
+					{
+						center.x = window.xMax - icon.width / 2;
+					}
+					// Along the right side, align the right edge of the icon with the right edge of the window.
+					else if (window.xMin < icon.width)
+					{
+						center.x = window.xMin + icon.width / 2;
+					}
+				}
+			}
+
+			// Assign the vector to the center of the rect.
+			icon.center = center;
+
+			// Return the icon's position.
+			return icon;
+		}
 				
 		private static ScreenMessage debugmsg = new ScreenMessage("", 2f, ScreenMessageStyle.UPPER_RIGHT);
 

--- a/VOID.csproj
+++ b/VOID.csproj
@@ -22,7 +22,7 @@
     <ConsolePause>false</ConsolePause>
     <CustomCommands>
       <CustomCommands>
-        <Command type="AfterBuild" command="/usr/bin/cp -fv ${ProjectDir}/bin/Debug/VOID.dll /mnt/games/ssd/KSP_linux/GameData/VOID/Plugins/" />
+        <Command type="AfterBuild" command="xcopy /Y ${ProjectDir}\bin\Debug\*.dll ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" workingdir="${ProjectDir}" externalConsole="True" />
       </CustomCommands>
     </CustomCommands>
   </PropertyGroup>
@@ -33,6 +33,11 @@
     <WarningLevel>4</WarningLevel>
     <ConsolePause>false</ConsolePause>
     <DefineConstants>TRACE</DefineConstants>
+    <CustomCommands>
+      <CustomCommands>
+        <Command type="AfterBuild" command="xcopy /Y ${ProjectDir}\bin\Release\*.dll ..\..\..\Games\KSP_win\GameData\VOID\Plugins\" workingdir="${ProjectDir}" externalConsole="True" />
+      </CustomCommands>
+    </CustomCommands>
   </PropertyGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
@@ -56,16 +61,13 @@
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\Assembly-CSharp.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine">
-      <HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\UnityEngine.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\UnityEngine.dll</HintPath>
     </Reference>
     <Reference Include="System">
-      <HintPath>..\..\..\..\..\mnt\games-ssd\KSP_linux\KSP_Data\Managed\System.dll</HintPath>
-      <Private>False</Private>
+      <HintPath>..\..\..\Games\KSP_win\KSP_Data\Managed\System.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>

--- a/VOIDFlightMaster.cs
+++ b/VOIDFlightMaster.cs
@@ -46,16 +46,17 @@
 
 		public void Awake()
 		{
-			Tools.PostDebugMessage ("VOIDLightMaster: Waking up.");
+			Tools.PostDebugMessage ("VOIDFlightMaster: Waking up.");
 			this.Core = (VOID_Core)VOID_Core.Instance;
-			this.Core.StartGUI ();
+			this.Core.ResetGUI ();
 			Tools.PostDebugMessage ("VOIDFlightMaster: Awake.");
 		}
 
 		public void Update()
 		{
-			if (!HighLogic.LoadedSceneIsEditor)
+			if (!HighLogic.LoadedSceneIsFlight && this.Core != null)
 			{
+				this.Core.SaveConfig ();
 				this.Core = null;
 				VOID_Core.Reset();
 				return;
@@ -70,7 +71,8 @@
 
 			if (this.Core.vessel != null)
 			{
-				SimManager.Instance.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter / Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2);
+				SimManager.Instance.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter /
+					Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2);
 				SimManager.Instance.TryStartSimulation();
 			}
 
@@ -91,6 +93,16 @@
 
 			this.Core.FixedUpdate ();
 		}
+
+		public void OnGUI()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnGUI();
+		}
     }
 
 	[KSPAddon(KSPAddon.Startup.EditorAny, false)]
@@ -102,14 +114,15 @@
 		{
 			Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");
 			this.Core = VOID_EditorCore.Instance;
-			this.Core.StartGUI ();
+			this.Core.ResetGUI ();
 			Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");
 		}
 
 		public void Update()
 		{
-			if (!HighLogic.LoadedSceneIsEditor)
+			if (!HighLogic.LoadedSceneIsEditor && this.Core != null)
 			{
+				this.Core.SaveConfig ();
 				this.Core = null;
 				VOID_EditorCore.Reset();
 				return;
@@ -139,6 +152,16 @@
 
 			this.Core.FixedUpdate ();
 		}
+
+		public void OnGUI()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnGUI();
+		}
 	}
 }
 

--- a/VOID_Core.cs
+++ b/VOID_Core.cs
@@ -68,7 +68,7 @@
 		 * Fields
 		 * */
 		protected string VoidName = "VOID";
-		protected string VoidVersion = "0.9.9";
+		protected string VoidVersion = "0.9.10";
 
 		protected bool _factoryReset = false;
 
@@ -97,6 +97,7 @@
 		protected Texture2D VOIDIconTexture;
 		protected string VOIDIconOnPath = "VOID/Textures/void_icon_on";
 		protected string VOIDIconOffPath = "VOID/Textures/void_icon_off";
+		protected bool VOIDIconLocked = true;
 
 		protected int windowBaseID = -96518722;
 		protected int _windowID = 0;
@@ -129,8 +130,9 @@
 
 		public float saveTimer = 0;
 
-		protected string defaultSkin = "KSP window 2";
-		protected VOID_SaveValue<int> _skinIdx = int.MinValue;
+		[AVOID_SaveValue("defaultSkin")]
+		protected VOID_SaveValue<string> defaultSkin = "KSP window 2";
+		protected int _skinIdx = int.MinValue;
 		protected List<GUISkin> skin_list;
 		protected string[] forbiddenSkins =
 		{
@@ -245,6 +247,13 @@
 				));
 			foreach (var voidType in types)
 			{
+				if (!HighLogic.LoadedSceneIsEditor &&
+				    typeof(IVOID_EditorModule).IsAssignableFrom(voidType)
+				    )
+				{
+					continue;
+				}
+
 				Tools.PostDebugMessage (string.Format (
 					"{0}: found Type {1}",
 					this.GetType ().Name,
@@ -286,19 +295,22 @@
 			));
 		}
 
+		protected void Preload_BeforeUpdate()
+		{
+			if (!this.bodiesLoaded)
+			{
+				this.LoadAllBodies();
+			}
+
+			if (!this.vesselTypesLoaded)
+			{
+				this.LoadVesselTypes();
+			}
+		}
+
 		public void Update()
 		{
-			this.saveTimer += Time.deltaTime;
-
-			if (!this.bodiesLoaded)
-			{
-				this.LoadAllBodies();
-			}
-
-			if (!this.vesselTypesLoaded)
-			{
-				this.LoadVesselTypes();
-			}
+			this.Preload_BeforeUpdate ();
 
 			if (!this.guiRunning)
 			{
@@ -331,11 +343,7 @@
 				}
 			}
 
-			if (this.saveTimer > 2f)
-			{
-				this.SaveConfig ();
-				this.saveTimer = 0;
-			}
+			this.CheckAndSave ();
 		}
 
 		public void FixedUpdate()
@@ -426,16 +434,48 @@
 			this.vesselTypesLoaded = true;
 		}
 
+		protected void CheckAndSave()
+		{
+			this.saveTimer += Time.deltaTime;
+
+			Tools.PostDebugMessage (string.Format (
+				"{0}: Checking if time to save; saveTimer: {1}",
+				this.GetType ().Name,
+				this.saveTimer
+			));
+
+			if (this.saveTimer > 2f)
+			{
+				Tools.PostDebugMessage (string.Format (
+					"{0}: Time to save, checking if configDirty: {1}",
+					this.GetType ().Name,
+					this.configDirty
+					));
+
+				if (!this.configDirty)
+				{
+					return;
+				}
+
+				this.SaveConfig ();
+				this.saveTimer = 0;
+			}
+		}
+
 		public void VOIDMainWindow(int _)
 		{
 			GUILayout.BeginVertical();
 			
-			if (this.powerAvailable)
-			{
-				string str = "ON";
-				if (togglePower) str = "OFF";
-				if (GUILayout.Button("Power " + str)) togglePower = !togglePower;
-			    if (togglePower)
+			if (this.powerAvailable || HighLogic.LoadedSceneIsEditor)
+			{
+				if (!HighLogic.LoadedSceneIsEditor)
+				{
+					string str = "ON";
+					if (togglePower) str = "OFF";
+					if (GUILayout.Button("Power " + str)) togglePower = !togglePower;
+				}
+
+				if (togglePower || HighLogic.LoadedSceneIsEditor)
 			    {
 					foreach (IVOID_Module module in this.Modules)
 					{
@@ -469,7 +509,12 @@
 
 		public override void DrawConfigurables()
 		{
-			this.consumeResource = GUILayout.Toggle (this.consumeResource, "Consume Resources");
+			if (HighLogic.LoadedSceneIsFlight)
+			{
+				this.consumeResource = GUILayout.Toggle (this.consumeResource, "Consume Resources");
+
+				this.VOIDIconLocked = GUILayout.Toggle (this.VOIDIconLocked, "Lock Icon Position");
+			}
 
 			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
@@ -483,7 +528,12 @@
 			{
 				this._skinIdx--;
 				if (this._skinIdx < 0) this._skinIdx = skin_list.Count - 1;
-				Tools.PostDebugMessage("[VOID] new this._skin = " + this._skinIdx + " :: skin_list.Count = " + skin_list.Count);
+				Tools.PostDebugMessage (string.Format (
+					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
+					this.GetType().Name,
+					this._skinIdx,
+					this.skin_list.Count
+				));
 			}
 
 			string skin_name = skin_list[this._skinIdx].name;
@@ -497,7 +547,17 @@
 			{
 				this._skinIdx++;
 				if (this._skinIdx >= skin_list.Count) this._skinIdx = 0;
-				Tools.PostDebugMessage("[VOID] new this._skin = " + this._skinIdx + " :: skin_list.Count = " + skin_list.Count);
+				Tools.PostDebugMessage (string.Format (
+					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
+					this.GetType().Name,
+					this._skinIdx,
+					this.skin_list.Count
+					));
+			}
+
+			if (this.Skin.name != this.defaultSkin)
+			{
+				this.defaultSkin = this.Skin.name;
 			}
 
 			GUILayout.EndHorizontal();
@@ -508,6 +568,59 @@
 			}
 
 			this._factoryReset = GUILayout.Toggle (this._factoryReset, "Factory Reset");
+		}
+
+		public void OnGUI()
+		{
+			if (Event.current.type == EventType.Repaint)
+			{
+				return;
+			}
+
+			Tools.PostDebugMessage(string.Format(
+				"Event.current.type: {0}" +
+				"\nthis.VOIDIconLocked: {1}" +
+				"\nEvent.current.mousePosition: {2}" +
+				"\nVOIDIconPos: ({3}, {4}),({5}, {6})",
+				Event.current.type,
+				this.VOIDIconLocked,
+				Event.current.mousePosition,
+				this.VOIDIconPos.value.xMin,
+				this.VOIDIconPos.value.yMin,
+				this.VOIDIconPos.value.xMax,
+				this.VOIDIconPos.value.yMax
+				));
+
+			if (!this.VOIDIconLocked &&
+			    VOIDIconPos.value.Contains(Event.current.mousePosition)
+			    && Event.current.type == EventType.mouseDrag
+			    )
+			{
+				Tools.PostDebugMessage(string.Format(
+					"Event.current.type: {0}" +
+					"\ndelta.x: {1}; delta.y: {2}",
+					Event.current.type,
+					Event.current.delta.x,
+					Event.current.delta.y
+				));
+
+				Rect tmp = new Rect(VOIDIconPos);
+
+				tmp.x = Event.current.mousePosition.x - tmp.width / 2;
+				tmp.y = Event.current.mousePosition.y - tmp.height / 2;
+
+				if (tmp.x > Screen.width - tmp.width)
+				{
+					tmp.x = Screen.width - tmp.width;
+				}
+
+				if (tmp.y > Screen.height - tmp.height)
+				{
+					tmp.y = Screen.height - tmp.height;
+				}
+
+				VOIDIconPos = tmp;
+			}
 		}
 
 		public override void DrawGUI()
@@ -533,7 +646,7 @@
 
 			this.VOIDIconTexture = this.VOIDIconOff;  //icon off default
 			if (this.togglePower) this.VOIDIconTexture = this.VOIDIconOn;     //or on if power_toggle==true
-			if (GUI.Button(new Rect(VOIDIconPos), VOIDIconTexture, new GUIStyle()))
+			if (GUI.Button(VOIDIconPos, VOIDIconTexture, new GUIStyle()) && this.VOIDIconLocked)
 			{
 				this.mainGuiMinimized = !this.mainGuiMinimized;
 			}
@@ -551,6 +664,8 @@
 					GUILayout.Height (50)
 				);
 
+				_mainWindowPos = Tools.ClampRectToScreen (_mainWindowPos);
+
 				if (_mainWindowPos != this.mainWindowPos)
 				{
 					this.mainWindowPos = _mainWindowPos;
@@ -570,6 +685,8 @@
 					GUILayout.Height (50)
 				);
 
+				_configWindowPos = Tools.ClampRectToScreen (_configWindowPos);
+
 				if (_configWindowPos != this.configWindowPos)
 				{
 					this.configWindowPos = _configWindowPos;
@@ -577,6 +694,19 @@
 			}
 		}
 
+		public void ResetGUI()
+		{
+			this.StopGUI ();
+
+			foreach (IVOID_Module module in this.Modules)
+			{
+				module.StopGUI ();
+				module.StartGUI ();
+			}
+
+			this.StartGUI ();
+		}
+
 		public override void LoadConfig()
 		{
 			base.LoadConfig ();
@@ -589,11 +719,6 @@
 
 		public void SaveConfig()
 		{
-			if (!this.configDirty)
-			{
-				return;
-			}
-
 			var config = KSP.IO.PluginConfiguration.CreateForType<VOID_Core> ();
 			config.load ();
 

--- a/VOID_EditorCore.cs
+++ b/VOID_EditorCore.cs
@@ -70,12 +70,25 @@
 			this._Name = "VOID Editor Core";
 		}
 
+		public new void OnGUI() {}
+
 		public override void DrawGUI()
 		{
 			if (!this._modulesLoaded)
 			{
 				this.LoadModulesOfType<IVOID_EditorModule>();
 			}
+
+			Rect _iconPos = Tools.DockToWindow (this.VOIDIconPos, this.mainWindowPos);
+
+			_iconPos = Tools.ClampRectToScreen (_iconPos, (int)_iconPos.width, (int)_iconPos.height);
+
+			if (_iconPos != this.VOIDIconPos)
+			{
+				this.VOIDIconPos = _iconPos;
+			}
+
+			base.DrawGUI();
 		}
 
 		public new void Update()
@@ -97,12 +110,12 @@
 				}
 			}
 
-			if (EditorLogic.startPod == null)
+			if (EditorLogic.startPod == null || !HighLogic.LoadedSceneIsEditor)
 			{
 				this.StopGUI();
 				return;
 			}
-			else if (!this.guiRunning)
+			else if (!this.guiRunning && HighLogic.LoadedSceneIsEditor)
 			{
 				this.StartGUI();
 			}
@@ -112,6 +125,8 @@
 				SimManager.Instance.Gravity = 9.08665;
 				SimManager.Instance.TryStartSimulation();
 			}
+
+			this.CheckAndSave ();
 		}
 
 		public new void FixedUpdate() {}

--- a/VOID_EditorHUD.cs
+++ b/VOID_EditorHUD.cs
@@ -81,7 +81,7 @@
 			this.textColors.Add(Color.magenta);
 
 			this.labelStyle = new GUIStyle ();
-			this.labelStyle.alignment = TextAnchor.UpperRight;
+			// this.labelStyle.alignment = TextAnchor.UpperRight;
 			this.labelStyle.normal.textColor = this.textColors [this.ColorIndex];
 
 			Tools.PostDebugMessage (this.GetType().Name + ": Constructed.");
@@ -96,12 +96,29 @@
 				return;
 			}
 
+			float hudLeft;
+
+			if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Parts)
+			{
+				hudLeft = EditorPanels.Instance.partsPanelWidth + 10;
+			}
+			else if (EditorLogic.fetch.editorScreen == EditorLogic.EditorScreen.Actions)
+			{
+				hudLeft = EditorPanels.Instance.actionsPanelWidth + 10;
+			}
+			else
+			{
+				return;
+			}
+
+			Rect hudPos = new Rect (hudLeft, 48, 300, 32);
+
 			// GUI.skin = AssetBase.GetGUISkin("KSP window 2");
 
 			labelStyle.normal.textColor = textColors [ColorIndex];
 
 			GUI.Label (
-				new Rect (Screen.width - 310, 80, 300f, 32f),
+				hudPos,
 				"Total Mass: " + SimManager.Instance.LastStage.totalMass.ToString("F3") + "t" +
 				" Part Count: " + EditorLogic.SortedShipList.Count +
 				"\nTotal Delta-V: " + Tools.MuMech_ToSI(SimManager.Instance.LastStage.totalDeltaV) + "m/s" +

--- a/VOID_Module.cs
+++ b/VOID_Module.cs
@@ -208,6 +208,8 @@
 				GUILayout.Height(this.defHeight)
 			);
 
+			_Pos = Tools.ClampRectToScreen (_Pos);
+
 			if (_Pos != this.WindowPos)
 			{
 				this.WindowPos = _Pos;

--- a/VOID_SaveValue.cs
+++ b/VOID_SaveValue.cs
@@ -77,10 +77,17 @@
 			VOID_SaveValue<T> r = new VOID_SaveValue<T>();
 			r.value = v;
 			r.type = v.GetType();
+
 			if (VOID_Core.Initialized)
 			{
 				VOID_Core.Instance.configDirty = true;
 			}
+
+			if (VOID_EditorCore.Initialized)
+			{
+				VOID_EditorCore.Instance.configDirty = true;
+			}
+
 			return r;
 		}