VOID_Core: Properly refuse to use the Toolbar if it is not available.
[VOID.git] / VOID_Core.cs
blob:a/VOID_Core.cs -> blob:b/VOID_Core.cs
--- a/VOID_Core.cs
+++ b/VOID_Core.cs
@@ -31,6 +31,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Text;
 using ToadicusTools;
 using UnityEngine;
 
@@ -38,6 +39,7 @@
 {
 	public class VOID_Core : VOID_Module, IVOID_Module
 	{
+		#region Singleton Members
 		/*
 		 * Static Members
 		 * */
@@ -69,16 +71,19 @@
 		public static void Reset()
 		{
 			_instance.StopGUI();
+			_instance.Dispose();
 			_instance = null;
 			_initialized = false;
 		}
-
-		public static double Constant_G = 6.674e-11;
+		#endregion
+
+		public static readonly double Constant_G = 6.674e-11;
+
 		/*
 		 * Fields
 		 * */
 		protected string VoidName = "VOID";
-		protected string VoidVersion = "0.10.0";
+		protected string VoidVersion;
 
 		protected bool _factoryReset = false;
 
@@ -115,9 +120,8 @@
 		protected int _windowID = 0;
 
 		protected bool GUIStylesLoaded = false;
-		protected Dictionary<string, GUIStyle> _LabelStyles = new Dictionary<string, GUIStyle>();
-
-		protected CelestialBody _Kerbin;
+
+		protected CelestialBody _homeBody;
 
 		[AVOID_SaveValue("togglePower")]
 		public VOID_SaveValue<bool> togglePower = true;
@@ -136,6 +140,9 @@
 		protected VOID_SaveValue<double> _updatePeriod = 1001f / 15000f;
 		protected float _updateTimer = 0f;
 		protected string stringFrequency;
+
+		[AVOID_SaveValue("vesselSimActive")]
+		protected VOID_SaveValue<bool> vesselSimActive;
 
 		// Vessel Type Housekeeping
 		protected List<VesselType> _allVesselTypes = new List<VesselType>();
@@ -159,7 +166,8 @@
 				"ExpRecoveryDialogSkin",
 				"KSP window 5",
 				"KSP window 6",
-				"PartTooltipSkin"
+				"PartTooltipSkin",
+				"KSCContextMenuSkin"
 			};
 		protected bool skinsLoaded = false;
 
@@ -168,6 +176,8 @@
 		[AVOID_SaveValue("UseBlizzyToolbar")]
 		protected VOID_SaveValue<bool> _UseToolbarManager;
 		internal IButton ToolbarButton;
+
+		internal ApplicationLauncherButton AppLauncherButton;
 
 		/*
 		 * Properties
@@ -219,14 +229,6 @@
 			}
 		}
 
-		public Dictionary<string, GUIStyle> LabelStyles
-		{
-			get
-			{
-				return this._LabelStyles;
-			}
-		}
-
 		public List<CelestialBody> allBodies
 		{
 			get
@@ -235,19 +237,25 @@
 			}
 		}
 
-		public CelestialBody Kerbin
-		{
-			get
-			{
-				if (this._Kerbin == null)
-				{
-					if (FlightGlobals.Bodies != null)
+		public List<CelestialBody> sortedBodyList
+		{
+			get;
+			private set;
+		}
+
+		public CelestialBody HomeBody
+		{
+			get
+			{
+				if (this._homeBody == null)
+				{
+					if (Planetarium.fetch != null)
 					{
-						this._Kerbin = FlightGlobals.Bodies.First(b => b.name == "Kerbin");
+						this._homeBody = Planetarium.fetch.Home;
 					}
 				}
 
-				return this._Kerbin;
+				return this._homeBody;
 			}
 		}
 
@@ -273,6 +281,18 @@
 			{
 				return this._updatePeriod;
 			}
+		}
+
+		public Stage[] Stages
+		{
+			get;
+			protected set;
+		}
+
+		public Stage LastStage
+		{
+			get;
+			protected set;
 		}
 
 		protected IconState powerState
@@ -327,10 +347,24 @@
 				}
 				if (value == true)
 				{
+					if (this.AppLauncherButton != null)
+					{
+						ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
+						this.AppLauncherButton = null;
+					}
+
 					this.InitializeToolbarButton();
 				}
 
 				_UseToolbarManager.value = value;
+			}
+		}
+
+		protected virtual ApplicationLauncher.AppScenes appIconVisibleScenes
+		{
+			get
+			{
+				return ApplicationLauncher.AppScenes.FLIGHT;
 			}
 		}
 
@@ -356,17 +390,33 @@
 			if (!this.GUIStylesLoaded)
 			{
 				this.LoadGUIStyles();
+
+				Tools.PostDebugMessage(
+					this,
+					"ToolbarAvailable: {0}, UseToobarManager: {1}",
+					ToolbarManager.ToolbarAvailable,
+					this.UseToolbarManager);
 			}
 
 			if (!this.UseToolbarManager)
 			{
-				if (GUI.Button(VOIDIconPos, VOIDIconTexture, this.iconStyle) && this.VOIDIconLocked)
-				{
-					this.ToggleMainWindow();
+				if (this.AppLauncherButton == null)
+				{
+					Tools.PostDebugMessage(this,
+						"UseToolbarManager = false (ToolbarAvailable = {0}) and " +
+						"AppLauncherButton is null, making AppLauncher button.",
+						ToolbarManager.ToolbarAvailable
+					);
+					this.InitializeAppLauncherButton();
 				}
 			}
 			else if (this.ToolbarButton == null)
 			{
+				Tools.PostDebugMessage(this,
+					"UseToolbarManager = true (ToolbarAvailable = {0}) and " +
+					"ToolbarButton is null, making Toolbar button.",
+					ToolbarManager.ToolbarAvailable
+				);
 				this.InitializeToolbarButton();
 			}
 
@@ -378,13 +428,20 @@
 				_mainWindowPos = GUILayout.Window(
 					this.windowID,
 					_mainWindowPos,
-					this.VOIDMainWindow,
+					VOID_Tools.GetWindowHandler(this.VOIDMainWindow),
 					string.Join(" ", new string[] { this.VoidName, this.VoidVersion }),
 					GUILayout.Width(250),
 					GUILayout.Height(50)
 				);
 
-				_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					_mainWindowPos = Tools.ClampRectToEditorPad(_mainWindowPos);
+				}
+				else
+				{
+					_mainWindowPos = Tools.ClampRectToScreen(_mainWindowPos);
+				}
 
 				if (_mainWindowPos != this.mainWindowPos)
 				{
@@ -399,13 +456,20 @@
 				_configWindowPos = GUILayout.Window(
 					this.windowID,
 					_configWindowPos,
-					this.VOIDConfigWindow,
+					VOID_Tools.GetWindowHandler(this.VOIDConfigWindow),
 					string.Join(" ", new string[] { this.VoidName, "Configuration" }),
 					GUILayout.Width(250),
 					GUILayout.Height(50)
 				);
 
-				_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					_configWindowPos = Tools.ClampRectToEditorPad(_configWindowPos);
+				}
+				else
+				{
+					_configWindowPos = Tools.ClampRectToScreen(_configWindowPos);
+				}
 
 				if (_configWindowPos != this.configWindowPos)
 				{
@@ -414,7 +478,7 @@
 			}
 		}
 
-		public void OnGUI()
+		public virtual void OnGUI()
 		{
 			if (Event.current.type == EventType.Repaint)
 			{
@@ -468,15 +532,14 @@
 			}
 		}
 
-		public void Update()
+		public virtual void Update()
 		{
 			this.LoadBeforeUpdate();
 
-			if (this.vessel != null)
-			{
-				SimManager.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter /
-					Math.Pow(VOID_Core.Instance.vessel.Radius(), 2);
-				SimManager.TryStartSimulation();
+			if (this.vessel != null && this.vesselSimActive)
+			{
+				Tools.PostDebugMessage(this, "Updating SimManager.");
+				this.UpdateSimManager();
 			}
 
 			if (!this.guiRunning)
@@ -513,7 +576,7 @@
 			this._updateTimer += Time.deltaTime;
 		}
 
-		public void FixedUpdate()
+		public virtual void FixedUpdate()
 		{
 			bool newPowerState = this.powerAvailable;
 
@@ -542,10 +605,23 @@
 				}
 			}
 
-			foreach (IVOID_BehaviorModule module in
-			         this._modules.OfType<IVOID_BehaviorModule>().Where(m => !m.GetType().IsAbstract))
-			{
-				module.FixedUpdate();
+			foreach (IVOID_Module module in this.Modules)
+			{
+				if (module is IVOID_BehaviorModule)
+				{
+					((IVOID_BehaviorModule)module).FixedUpdate();
+				}
+			}
+		}
+
+		public void OnDestroy()
+		{
+			foreach (IVOID_Module module in this.Modules)
+			{
+				if (module is IVOID_BehaviorModule)
+				{
+					((IVOID_BehaviorModule)module).OnDestroy();
+				}
 			}
 		}
 
@@ -590,7 +666,7 @@
 			}
 			else
 			{
-				GUILayout.Label("-- POWER LOST --", this.LabelStyles["red"]);
+				GUILayout.Label("-- POWER LOST --", VOID_Styles.labelRed);
 			}
 
 			this.configWindowMinimized.value = !GUILayout.Toggle(!this.configWindowMinimized, "Configuration");
@@ -621,6 +697,9 @@
 			}
 
 			this.UseToolbarManager = GUILayout.Toggle(this.UseToolbarManager, "Use Blizzy's Toolbar If Available");
+
+			this.vesselSimActive.value = GUILayout.Toggle(this.vesselSimActive.value,
+				"Enable Engineering Calculations");
 
 			GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 
@@ -632,7 +711,6 @@
 			_content.tooltip = "Select previous skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this.GUIStylesLoaded = false;
 				this._skinIdx--;
 				Tools.PostDebugMessage(string.Format(
 					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
@@ -644,13 +722,12 @@
 
 			_content.text = this.Skin.name;
 			_content.tooltip = "Current skin";
-			GUILayout.Label(_content, this.LabelStyles["center"], GUILayout.ExpandWidth(true));
+			GUILayout.Label(_content, VOID_Styles.labelCenter, GUILayout.ExpandWidth(true));
 
 			_content.text = "►";
 			_content.tooltip = "Select next skin";
 			if (GUILayout.Button(_content, GUILayout.ExpandWidth(true)))
 			{
-				this.GUIStylesLoaded = false;
 				this._skinIdx++;
 				Tools.PostDebugMessage(string.Format(
 					"{0}: new this._skinIdx = {1} :: skin_list.Count = {2}",
@@ -669,6 +746,7 @@
 			if (this._skinName != skinNames[this._skinIdx])
 			{
 				this._skinName.value = skinNames[this._skinIdx];
+				this.GUIStylesLoaded = false;
 			}
 
 			GUILayout.EndHorizontal();
@@ -680,7 +758,7 @@
 				this.stringFrequency = (1f / this.updatePeriod).ToString();
 			}
 			this.stringFrequency = GUILayout.TextField(this.stringFrequency.ToString(), 5, GUILayout.ExpandWidth(true));
-			// GUILayout.FlexibleSpace();
+
 			if (GUILayout.Button("Apply"))
 			{
 				double updateFreq = 1f / this.updatePeriod;
@@ -697,45 +775,89 @@
 			this._factoryReset = GUILayout.Toggle(this._factoryReset, "Factory Reset");
 		}
 
+		protected void UpdateSimManager()
+		{
+			if (SimManager.ResultsReady())
+			{
+				Tools.PostDebugMessage(this, "VesselSimulator results ready, setting Stages.");
+
+				this.Stages = SimManager.Stages;
+
+				if (this.Stages != null)
+				{
+					this.LastStage = this.Stages.Last();
+				}
+
+				if (HighLogic.LoadedSceneIsEditor)
+				{
+					SimManager.Gravity = VOID_Data.KerbinGee;
+				}
+				else
+				{
+					double radius = this.vessel.Radius();
+					SimManager.Gravity = this.vessel.mainBody.gravParameter / (radius * radius);
+				}
+
+				SimManager.minSimTime = (long)(this.updatePeriod * 1000);
+
+				SimManager.TryStartSimulation();
+			}
+			#if DEBUG
+			else
+			{
+				Tools.PostDebugMessage(this, "VesselSimulator results not ready.");
+			}
+			#endif
+		}
+
 		protected void LoadModulesOfType<T>()
 		{
-			var types = AssemblyLoader.loadedAssemblies
-				.Select(a => a.assembly.GetExportedTypes())
-				.SelectMany(t => t)
-				.Where(v => typeof(T).IsAssignableFrom(v)
-					&& !(v.IsInterface || v.IsAbstract) &&
-					!typeof(VOID_Core).IsAssignableFrom(v)
-				);
-
-			Tools.PostDebugMessage(string.Format(
-				"{0}: Found {1} modules to check.",
-				this.GetType().Name,
-				types.Count()
-			));
-			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,
-					voidType.Name
-				));
-
-				this.LoadModule(voidType);
+			StringBuilder sb = new StringBuilder("Loading modules...");
+			sb.AppendLine();
+
+			foreach (AssemblyLoader.LoadedAssembly assy in AssemblyLoader.loadedAssemblies)
+			{
+				foreach (Type loadedType in assy.assembly.GetExportedTypes())
+				{
+					if (
+						loadedType.IsInterface ||
+						loadedType.IsAbstract ||
+						!typeof(T).IsAssignableFrom(loadedType) ||
+						this.GetType().IsAssignableFrom(loadedType)
+					)
+					{
+						continue;
+					}
+
+					// HACK: This stops editor modules from loading in flight.  It is a dirty hack and should be fixed.
+					if (!HighLogic.LoadedSceneIsEditor && typeof(IVOID_EditorModule).IsAssignableFrom(loadedType))
+					{
+						continue;
+					}
+
+					sb.AppendFormat("Loading IVOID_Module type {0}...", loadedType.Name);
+
+					try
+					{
+						this.LoadModule(loadedType);
+						sb.AppendLine("Success.");
+					}
+					catch (Exception ex)
+					{
+						sb.AppendFormat("Failed, caught {0}", ex.GetType().Name);
+						sb.AppendLine();
+
+						#if DEBUG
+						Debug.LogException(ex);
+						#endif
+					}
+				}
 			}
 
 			this._modulesLoaded = true;
 
-			Tools.PostDebugMessage(string.Format(
-				"{0}: Loaded {1} modules.",
-				this.GetType().Name,
-				this.Modules.Count
-			));
+			sb.AppendFormat("Loaded {0} modules.", this.Modules.Count);
+			sb.AppendLine();
 		}
 
 		protected void LoadModule(Type T)
@@ -821,32 +943,7 @@
 
 		protected void LoadGUIStyles()
 		{
-			this.LabelStyles["link"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["link"].fontStyle = FontStyle.Bold;
-
-			this.LabelStyles["center"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["center"].normal.textColor = Color.white;
-			this.LabelStyles["center"].alignment = TextAnchor.UpperCenter;
-
-			this.LabelStyles["center_bold"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["center_bold"].normal.textColor = Color.white;
-			this.LabelStyles["center_bold"].alignment = TextAnchor.UpperCenter;
-			this.LabelStyles["center_bold"].fontStyle = FontStyle.Bold;
-
-			this.LabelStyles["right"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["right"].normal.textColor = Color.white;
-			this.LabelStyles["right"].alignment = TextAnchor.UpperRight;
-
-			this.LabelStyles["red"] = new GUIStyle(GUI.skin.label);
-			this.LabelStyles["red"].normal.textColor = Color.red;
-			this.LabelStyles["red"].alignment = TextAnchor.MiddleCenter;
-
-			this.iconStyle = new GUIStyle(GUI.skin.button);
-			this.iconStyle.padding = new RectOffset(0, 0, 0, 0);
-			// this.iconStyle.margin = new RectOffset(0, 0, 0, 0);
-			// this.iconStyle.contentOffset = new Vector2(0, 0);
-			this.iconStyle.overflow = new RectOffset(0, 0, 0, 0);
-			// this.iconStyle.border = new RectOffset(0, 0, 0, 0);
+			VOID_Styles.OnSkinChanged();
 
 			this.GUIStylesLoaded = true;
 		}
@@ -863,13 +960,24 @@
 			{
 				this.LoadVesselTypes();
 			}
+
+			if (this.sortedBodyList == null && FlightGlobals.Bodies != null && FlightGlobals.Bodies.Count > 0)
+			{
+				this.sortedBodyList = new List<CelestialBody>(FlightGlobals.Bodies);
+				this.sortedBodyList.Sort(new CBListComparer());
+				this.sortedBodyList.Reverse();
+
+				Debug.Log(string.Format("sortedBodyList: {0}", string.Join("\n\t", this.sortedBodyList.Select(b => b.bodyName).ToArray())));
+			}
+
 		}
 
 		protected void InitializeToolbarButton()
 		{
-			// Do nothing if the Toolbar is not available.
+			// Do nothing if (the Toolbar is not available.
 			if (!ToolbarManager.ToolbarAvailable)
 			{
+				Tools.PostDebugMessage(this, "Refusing to make a ToolbarButton: ToolbarAvailable = false");
 				return;
 			}
 
@@ -886,6 +994,27 @@
 			};
 
 			Tools.PostDebugMessage(string.Format("{0}: Toolbar Button initialized.", this.GetType().Name));
+		}
+
+		protected void InitializeAppLauncherButton()
+		{
+			if (ApplicationLauncher.Ready)
+			{
+				this.AppLauncherButton = ApplicationLauncher.Instance.AddModApplication(
+					this.ToggleMainWindow, this.ToggleMainWindow,
+					this.appIconVisibleScenes,
+					this.VOIDIconTexture
+				);
+
+				Tools.PostDebugMessage(
+					this,
+					"AppLauncherButton initialized in {0}",
+					Enum.GetName(
+						typeof(GameScenes),
+						HighLogic.LoadedScene
+					)
+				);
+			}
 		}
 
 		protected void ToggleMainWindow()
@@ -922,7 +1051,12 @@
 				this.ToolbarButton.TexturePath = texturePath;
 			}
 
-			this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath, false);
+			this.VOIDIconTexture = GameDatabase.Instance.GetTexture(texturePath.Replace("icon", "appIcon"), false);
+
+			if (this.AppLauncherButton != null)
+			{
+				this.AppLauncherButton.SetTexture(VOIDIconTexture);
+			}
 		}
 
 		protected void CheckAndSave()
@@ -978,7 +1112,11 @@
 		{
 			this._Name = "VOID Core";
 
-			this._Active.value = true;
+			System.Version version = this.GetType().Assembly.GetName().Version;
+
+			this.VoidVersion = string.Format("{0}.{1}.{2}", version.Major, version.Minor, version.MajorRevision);
+
+			this.toggleActive = true;
 
 			this._skinName = this.defaultSkin;
 			this._skinIdx = int.MinValue;
@@ -988,11 +1126,27 @@
 			this.VOIDIconOffInactivePath = "VOID/Textures/void_icon_light";
 			this.VOIDIconOffActivePath = "VOID/Textures/void_icon_dark";
 
+			this.vesselSimActive = true;
+
 			this.UseToolbarManager = false;
 
 			this.LoadConfig();
 
 			this.SetIconTexture(this.powerState | this.activeState);
+		}
+
+		public virtual void Dispose()
+		{
+			if (this.AppLauncherButton != null)
+			{
+				ApplicationLauncher.Instance.RemoveModApplication(this.AppLauncherButton);
+				this.AppLauncherButton = null;
+			}
+			if (this.ToolbarButton != null)
+			{
+				this.ToolbarButton.Destroy();
+				this.ToolbarButton = null;
+			}
 		}
 
 		protected enum IconState
@@ -1003,25 +1157,6 @@
 			Active = 8
 		}
 	}
-
-	public static partial class VOID_Data
-	{
-		public static VOID_Core core
-		{
-			get
-			{
-				return VOID_Core.Instance;
-			}
-		}
-
-		public static double KerbinGee
-		{
-			get
-			{
-				return core.Kerbin.gravParameter / Math.Pow(core.Kerbin.Radius, 2);
-			}
-		}
-	}
 }