VOID_Core: Change to use the same Toolbar button for both editor and flight drivers.
VOID_Core: Change to use the same Toolbar button for both editor and flight drivers.

file:a/Tools.cs -> file:b/Tools.cs
--- a/Tools.cs
+++ b/Tools.cs
@@ -1001,6 +1001,30 @@
 			}
 		}
 
+		public static double Radius(this Vessel vessel)
+		{
+			double radius;
+
+			radius = vessel.altitude;
+
+			if (vessel.mainBody != null)
+			{
+				radius += vessel.mainBody.Radius;
+			}
+
+			return radius;
+		}
+
+		public static double TryGetLastMass(this Engineer.VesselSimulator.SimManager simManager)
+		{
+			if (simManager.Stages == null || simManager.Stages.Length <= Staging.lastStage)
+			{
+				return double.NaN;
+			}
+
+			return simManager.Stages[Staging.lastStage].totalMass;
+		}
+
 		public static string HumanString(this ExperimentSituations situation)
 		{
 			switch (situation)

--- /dev/null
+++ b/VOIDEditorMaster.cs
@@ -1,1 +1,100 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+//    VOID - Vessel Orbital Information Display for Kerbal Space Program
+//    Copyright (C) 2012 Iannic-ann-od
+//    Copyright (C) 2013 Toadicus
+//
+//    This program is free software: you can redistribute it and/or modify
+//    it under the terms of the GNU General Public License as published by
+//    the Free Software Foundation, either version 3 of the License, or
+//    (at your option) any later version.
+//
+//    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.
+//
+//    You should have received a copy of the GNU General Public License
+//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+///////////////////////////////////////////////////////////////////////////////
+//
+//  Much, much credit to Younata, Adammada, Nivvydaskrl and to all the authors
+//  behind MechJeb, RemoteTech Relay Network, ISA MapSat, and Protractor for some
+//  invaluable functions and making your nicely written code available to learn from.
+//
+///////////////////////////////////////////////////////////////////////////////
+//
+//  This software uses VesselSimulator and Engineer.Extensions from Engineer Redux.
+//  Engineer Redux (c) 2013 cybutek
+//  Used by permission.
+//
+///////////////////////////////////////////////////////////////////////////////
 
+using System;
+using UnityEngine;
+using Engineer.VesselSimulator;
+
+namespace VOID
+{
+	[KSPAddon(KSPAddon.Startup.EditorAny, false)]
+	public class VOIDEditorMaster : MonoBehaviour
+	{
+		protected VOID_EditorCore Core;
+
+		public void Awake()
+		{
+			Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");
+			this.Core = VOID_EditorCore.Instance;
+			this.Core.ResetGUI ();
+			SimManager.HardReset();
+			Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");
+		}
+
+		public void Update()
+		{
+			if (!HighLogic.LoadedSceneIsEditor && this.Core != null)
+			{
+				this.Core.SaveConfig ();
+				this.Core = null;
+				VOID_EditorCore.Reset();
+				return;
+			}
+
+			if (this.Core == null)
+			{
+				this.Awake();
+			}
+
+			this.Core.Update ();
+
+			if (this.Core.factoryReset)
+			{
+				KSP.IO.File.Delete<VOID_EditorCore>("config.xml");
+				this.Core = null;
+				VOID_EditorCore.Reset();
+			}
+		}
+
+		public void FixedUpdate()
+		{
+			if (this.Core == null || !HighLogic.LoadedSceneIsEditor)
+			{
+				return;
+			}
+
+			this.Core.FixedUpdate ();
+		}
+
+		public void OnGUI()
+		{
+			if (this.Core == null)
+			{
+				return;
+			}
+
+			this.Core.OnGUI();
+		}
+	}
+}
+

--- a/VOIDFlightMaster.cs
+++ b/VOIDFlightMaster.cs
@@ -96,65 +96,5 @@
 			this.Core.OnGUI();
 		}
     }
-
-	[KSPAddon(KSPAddon.Startup.EditorAny, false)]
-	public class VOIDEditorMaster : MonoBehaviour
-	{
-		protected VOID_EditorCore Core;
-
-		public void Awake()
-		{
-			Tools.PostDebugMessage ("VOIDEditorMaster: Waking up.");
-			this.Core = VOID_EditorCore.Instance;
-			this.Core.ResetGUI ();
-			SimManager.HardReset();
-			Tools.PostDebugMessage ("VOIDEditorMaster: Awake.");
-		}
-
-		public void Update()
-		{
-			if (!HighLogic.LoadedSceneIsEditor && this.Core != null)
-			{
-				this.Core.SaveConfig ();
-				this.Core = null;
-				VOID_EditorCore.Reset();
-				return;
-			}
-
-			if (this.Core == null)
-			{
-				this.Awake();
-			}
-
-			this.Core.Update ();
-
-			if (this.Core.factoryReset)
-			{
-				KSP.IO.File.Delete<VOID_EditorCore>("config.xml");
-				this.Core = null;
-				VOID_EditorCore.Reset();
-			}
-		}
-
-		public void FixedUpdate()
-		{
-			if (this.Core == null || !HighLogic.LoadedSceneIsEditor)
-			{
-				return;
-			}
-
-			this.Core.FixedUpdate ();
-		}
-
-		public void OnGUI()
-		{
-			if (this.Core == null)
-			{
-				return;
-			}
-
-			this.Core.OnGUI();
-		}
-	}
 }
 

--- a/VOID_CBInfoBrowser.cs
+++ b/VOID_CBInfoBrowser.cs
@@ -98,8 +98,6 @@
 			GUILayout.EndVertical();
 
 			GUILayout.EndHorizontal();
-
-			//}
 
 			//toggle for orbital info chunk
 			if (GUILayout.Button("Orbital Characteristics", GUILayout.ExpandWidth(true))) toggleOrbital.value = !toggleOrbital;
@@ -206,84 +204,53 @@
 
 		private void body_OP_show_orbital_info(CelestialBody body)
 		{
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.ApA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToAp), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.PeA / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(Tools.ConvertInterval(body.orbit.timeToPe), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.semiMajorAxis / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(body.orbit.eccentricity.ToString("F4") + "", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(Tools.ConvertInterval(body.orbit.period), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(Tools.ConvertInterval(body.rotationPeriod), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.orbitalSpeed / 1000).ToString("F2") + "km/s", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			// Toadicus edit: convert mean anomaly into degrees.
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.meanAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(body.orbit.trueAnomaly.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			// Toadicus edit: convert eccentric anomaly into degrees.
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label((body.orbit.eccentricAnomaly * 180d / Math.PI).ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(body.orbit.inclination.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(body.orbit.LAN.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else GUILayout.Label(body.orbit.argumentOfPeriapsis.ToString("F3") + "°", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-		    //GUILayout.EndHorizontal();
-
-		    //GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 		    if (body.bodyName == "Sun") GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    else
 		    {
@@ -291,42 +258,28 @@
 		        if (body.tidallyLocked) body_tidally_locked = "Yes";
 		        GUILayout.Label(body_tidally_locked, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 		    }
-		    //GUILayout.EndHorizontal();
 		}
 
 		private void body_OP_show_physical_info(CelestialBody body)
 		{
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label((body.Radius / 1000).ToString("##,#") + "km", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label(((Math.Pow((body.Radius), 2) * 4 * Math.PI) / 1000).ToString("0.00e+00") + "km²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			// divide by 1000 to convert m to km
 			GUILayout.Label((((4d / 3) * Math.PI * Math.Pow(body.Radius, 3)) / 1000).ToString("0.00e+00") + "km³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.Label(((4 / 3) * Math.PI * Math.Pow((vessel.mainBody.Radius / 1000), 3)).ToString(), right, GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label(body.Mass.ToString("0.00e+00") + "kg", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
 
 			double p = body.Mass / (Math.Pow(body.Radius, 3) * (4d / 3) * Math.PI);
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label(p.ToString("##,#") + "kg/m³", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			if (body.bodyName == "Sun") GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
 			else GUILayout.Label(Tools.MuMech_ToSI(body.sphereOfInfluence), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label(body.orbitingBodies.Count.ToString(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
 
 			//show # artificial satellites
 			int num_art_sats = 0;
@@ -334,31 +287,33 @@
 			{
 				if (v.mainBody == body && v.situation.ToString() == "ORBITING") num_art_sats++;
 			}
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+				
 			GUILayout.Label(num_art_sats.ToString(), VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
 
 			double g_ASL = (VOID_Core.Constant_G * body.Mass) / Math.Pow(body.Radius, 2);
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
+
 			GUILayout.Label(Tools.MuMech_ToSI(g_ASL) + "m/s²", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			string O2 = "No";
-			if (body.atmosphereContainsOxygen == true) O2 = "Yes";
-			GUILayout.Label(O2, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
-
-			//GUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
-			string ocean = "No";
-			if (body.ocean == true) ocean = "Yes";
-			GUILayout.Label(ocean, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
-			//GUILayout.EndHorizontal();
+
+			if (body.atmosphere)
+			{
+				GUILayout.Label("≈ " + Tools.MuMech_ToSI(body.maxAtmosphereAltitude) + "m",
+					VOID_Core.Instance.LabelStyles["right"],
+					GUILayout.ExpandWidth(true));
+
+				string O2 = "No";
+				if (body.atmosphereContainsOxygen == true) O2 = "Yes";
+				GUILayout.Label(O2, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
+
+				string ocean = "No";
+				if (body.ocean == true) ocean = "Yes";
+				GUILayout.Label(ocean, VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			}
+			else
+			{
+				GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
+				GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
+				GUILayout.Label("N/A", VOID_Core.Instance.LabelStyles["right"], GUILayout.ExpandWidth(true));
+			}
 		}
 	}
 }

--- a/VOID_Core.cs
+++ b/VOID_Core.cs
@@ -108,6 +108,8 @@
 		protected bool GUIStylesLoaded = false;
 		protected Dictionary<string, GUIStyle> _LabelStyles = new Dictionary<string, GUIStyle>();
 
+		protected CelestialBody _Kerbin;
+
 		[AVOID_SaveValue("togglePower")]
 		public VOID_SaveValue<bool> togglePower = true;
 		public bool powerAvailable = true;
@@ -211,6 +213,22 @@
 			get
 			{
 				return FlightGlobals.Bodies;
+			}
+		}
+
+		public CelestialBody Kerbin
+		{
+			get
+			{
+				if (this._Kerbin == null)
+				{
+					if (FlightGlobals.Bodies != null)
+					{
+						this._Kerbin = FlightGlobals.Bodies.First(b => b.name == "Kerbin");
+					}
+				}
+
+				return this._Kerbin;
 			}
 		}
 
@@ -440,7 +458,7 @@
 			if (this.vessel != null)
 			{
 				SimManager.Instance.Gravity = VOID_Core.Instance.vessel.mainBody.gravParameter /
-				Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2);
+					Math.Pow(VOID_Core.Instance.vessel.Radius(), 2);
 				SimManager.Instance.TryStartSimulation();
 			}
 
@@ -831,18 +849,11 @@
 
 		protected void InitializeToolbarButton()
 		{
-			this.ToolbarButton = ToolbarManager.Instance.add(this.GetType().Name, "coreToggle");
+			this.ToolbarButton = ToolbarManager.Instance.add(this.VoidName, "coreToggle");
 			this.ToolbarButton.Text = this.VoidName;
 			this.SetIconTexture(this.powerState | this.activeState);
 
-			if (this is VOID_EditorCore)
-			{
-				this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR);
-			}
-			else
-			{
-				this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT);
-			}
+			this.ToolbarButton.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT, GameScenes.SPH);
 
 			this.ToolbarButton.OnClick += 
 				(e) =>

--- a/VOID_EditorCore.cs
+++ b/VOID_EditorCore.cs
@@ -122,7 +122,8 @@
 
 			if (EditorLogic.SortedShipList.Count > 0)
 			{
-				SimManager.Instance.Gravity = 9.08665;
+				SimManager.Instance.Gravity = this.Kerbin.gravParameter /
+					Math.Pow(this.Kerbin.Radius, 2);
 				SimManager.Instance.TryStartSimulation();
 			}
 

--- a/VOID_VesselInfo.cs
+++ b/VOID_VesselInfo.cs
@@ -43,7 +43,7 @@
 
 		protected VOID_DoubleValue totalMass = new VOID_DoubleValue(
 			"Total Mass",
-			new Func<double>(() => VOID_Core.Instance.vessel.GetTotalMass()),
+			new Func<double> (() => SimManager.Instance.TryGetLastMass()),
 			"tons"
 		);
 
@@ -118,7 +118,7 @@
 
 				double currThrust = SimManager.Instance.LastStage.actualThrust;
 				double maxThrust = SimManager.Instance.LastStage.thrust;
-				double mass = VOID_Core.Instance.vessel.GetTotalMass();
+				double mass = SimManager.Instance.TryGetLastMass();
 				double gravity = VOID_Core.Instance.vessel.mainBody.gravParameter /
 				                 Math.Pow(
 					                 VOID_Core.Instance.vessel.mainBody.Radius + VOID_Core.Instance.vessel.altitude,
@@ -142,7 +142,7 @@
 					return double.NaN;
 
 				double maxThrust = SimManager.Instance.LastStage.thrust;
-				double mass = VOID_Core.Instance.vessel.GetTotalMass();
+				double mass = SimManager.Instance.TryGetLastMass();
 				double gravity = (VOID_Core.Constant_G * VOID_Core.Instance.vessel.mainBody.Mass) /
 				                 Math.Pow(VOID_Core.Instance.vessel.mainBody.Radius, 2);
 				double weight = mass * gravity;
@@ -214,8 +214,6 @@
 				SimManager.Instance.RequestSimulation();
 			}
 
-			Stage[] stages = SimManager.Instance.Stages;
-
 			GUILayout.BeginVertical();
 
 			GUILayout.Label(

--- a/Wrapper/ToolbarWrapper.cs
+++ b/Wrapper/ToolbarWrapper.cs
@@ -71,11 +71,9 @@
 		public static IToolbarManager Instance {
 			get {
 				if ((toolbarAvailable != false) && (instance_ == null)) {
-					Type type = AssemblyLoader.loadedAssemblies
-						.SelectMany(a => a.assembly.GetExportedTypes())
-						.SingleOrDefault(t => t.FullName == "Toolbar.ToolbarManager");
+					Type type = ToolbarTypes.getType("Toolbar.ToolbarManager");
 					if (type != null) {
-						object realToolbarManager = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static).GetValue(null, null);
+						object realToolbarManager = ToolbarTypes.getStaticProperty(type, "Instance").GetValue(null, null);
 						instance_ = new ToolbarManager(realToolbarManager);
 					}
 				}
@@ -241,6 +239,15 @@
 		}
 
 		/// <summary>
+		/// A drawable that is tied to the current button. This can be anything from a popup menu to
+		/// an informational window. Set to null to hide the drawable.
+		/// </summary>
+		IDrawable Drawable {
+			set;
+			get;
+		}
+
+		/// <summary>
 		/// Event handler that can be registered with to receive "on click" events.
 		/// </summary>
 		/// <example>
@@ -286,6 +293,29 @@
 		void Destroy();
 	}
 
+	/// <summary>
+	/// A drawable that is tied to a particular button. This can be anything from a popup menu
+	/// to an informational window.
+	/// </summary>
+	public interface IDrawable {
+		/// <summary>
+		/// Update any information. This is called once per frame.
+		/// </summary>
+		void Update();
+
+		/// <summary>
+		/// Draws GUI widgets for this drawable. This is the equivalent to the OnGUI() message in
+		/// <see cref="MonoBehaviour"/>.
+		/// </summary>
+		/// <remarks>
+		/// The drawable will be positioned near its parent toolbar according to the drawable's current
+		/// width/height.
+		/// </remarks>
+		/// <param name="position">The left/top position of where to draw this drawable.</param>
+		/// <returns>The current width/height of this drawable.</returns>
+		Vector2 Draw(Vector2 position);
+	}
+
 	#endregion
 
 	#region events
@@ -389,12 +419,82 @@
 		private PropertyInfo visibleProperty;
 
 		public GameScenesVisibility(params GameScenes[] gameScenes) {
-			Type gameScenesVisibilityType = AssemblyLoader.loadedAssemblies
-				.SelectMany(a => a.assembly.GetExportedTypes())
-				.SingleOrDefault(t => t.FullName == "Toolbar.GameScenesVisibility");
+			Type gameScenesVisibilityType = ToolbarTypes.getType("Toolbar.GameScenesVisibility");
 			realGameScenesVisibility = Activator.CreateInstance(gameScenesVisibilityType, new object[] { gameScenes });
-			visibleProperty = gameScenesVisibilityType.GetProperty("Visible", BindingFlags.Public | BindingFlags.Instance);
+			visibleProperty = ToolbarTypes.getProperty(gameScenesVisibilityType, "Visible");
 			this.gameScenes = gameScenes;
+		}
+	}
+
+	#endregion
+
+	#region drawable
+
+	/// <summary>
+	/// A drawable that draws a popup menu.
+	/// </summary>
+	public partial class PopupMenuDrawable : IDrawable {
+		/// <summary>
+		/// Event handler that can be registered with to receive "any menu option clicked" events.
+		/// </summary>
+		public event Action OnAnyOptionClicked {
+			add {
+				onAnyOptionClickedEvent.AddEventHandler(realPopupMenuDrawable, value);
+			}
+			remove {
+				onAnyOptionClickedEvent.RemoveEventHandler(realPopupMenuDrawable, value);
+			}
+		}
+
+		private object realPopupMenuDrawable;
+		private MethodInfo updateMethod;
+		private MethodInfo drawMethod;
+		private MethodInfo addOptionMethod;
+		private MethodInfo addSeparatorMethod;
+		private MethodInfo destroyMethod;
+		private EventInfo onAnyOptionClickedEvent;
+
+		public PopupMenuDrawable() {
+			Type popupMenuDrawableType = ToolbarTypes.getType("Toolbar.PopupMenuDrawable");
+			realPopupMenuDrawable = Activator.CreateInstance(popupMenuDrawableType, null);
+			updateMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Update");
+			drawMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Draw");
+			addOptionMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddOption");
+			addSeparatorMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "AddSeparator");
+			destroyMethod = ToolbarTypes.getMethod(popupMenuDrawableType, "Destroy");
+			onAnyOptionClickedEvent = ToolbarTypes.getEvent(popupMenuDrawableType, "OnAnyOptionClicked");
+		}
+
+		public void Update() {
+			updateMethod.Invoke(realPopupMenuDrawable, null);
+		}
+
+		public Vector2 Draw(Vector2 position) {
+			return (Vector2) drawMethod.Invoke(realPopupMenuDrawable, new object[] { position });
+		}
+
+		/// <summary>
+		/// Adds a new option to the popup menu.
+		/// </summary>
+		/// <param name="text">The text of the option.</param>
+		/// <returns>A button that can be used to register clicks on the menu option.</returns>
+		public IButton AddOption(string text) {
+			object realButton = addOptionMethod.Invoke(realPopupMenuDrawable, new object[] { text });
+			return new Button(realButton, new ToolbarTypes());
+		}
+
+		/// <summary>
+		/// Adds a separator to the popup menu.
+		/// </summary>
+		public void AddSeparator() {
+			addSeparatorMethod.Invoke(realPopupMenuDrawable, null);
+		}
+
+		/// <summary>
+		/// Destroys this drawable. This must always be called before disposing of this drawable.
+		/// </summary>
+		public void Destroy() {
+			destroyMethod.Invoke(realPopupMenuDrawable, null);
 		}
 	}
 
@@ -409,28 +509,17 @@
 		private object realToolbarManager;
 		private MethodInfo addMethod;
 		private Dictionary<object, IButton> buttons = new Dictionary<object, IButton>();
-		private Type iButtonType;
-		private Type functionVisibilityType;
+		private ToolbarTypes types = new ToolbarTypes();
 
 		private ToolbarManager(object realToolbarManager) {
 			this.realToolbarManager = realToolbarManager;
 
-			Type iToolbarManagerType = AssemblyLoader.loadedAssemblies
-				.SelectMany(a => a.assembly.GetExportedTypes())
-				.SingleOrDefault(t => t.FullName == "Toolbar.IToolbarManager");
-			addMethod = iToolbarManagerType.GetMethod("add", BindingFlags.Public | BindingFlags.Instance);
-
-			iButtonType = AssemblyLoader.loadedAssemblies
-				.SelectMany(a => a.assembly.GetExportedTypes())
-				.SingleOrDefault(t => t.FullName == "Toolbar.IButton");
-			functionVisibilityType = AssemblyLoader.loadedAssemblies
-				.SelectMany(a => a.assembly.GetExportedTypes())
-				.SingleOrDefault(t => t.FullName == "Toolbar.FunctionVisibility");
+			addMethod = ToolbarTypes.getMethod(types.iToolbarManagerType, "add");
 		}
 
 		public IButton add(string ns, string id) {
 			object realButton = addMethod.Invoke(realToolbarManager, new object[] { ns, id });
-			IButton button = new Button(realButton, iButtonType, functionVisibilityType);
+			IButton button = new Button(realButton, types);
 			buttons.Add(realButton, button);
 			return button;
 		}
@@ -438,103 +527,79 @@
 
 	internal class Button : IButton {
 		private object realButton;
-		private PropertyInfo textProperty;
-		private PropertyInfo textColorProperty;
-		private PropertyInfo texturePathProperty;
-		private PropertyInfo toolTipProperty;
-		private PropertyInfo visibleProperty;
-		private PropertyInfo visibilityProperty;
-		private Type functionVisibilityType;
-		private PropertyInfo effectivelyVisibleProperty;
-		private PropertyInfo enabledProperty;
-		private PropertyInfo importantProperty;
-		private EventInfo onClickEvent;
+		private ToolbarTypes types;
 		private Delegate realClickHandler;
-		private EventInfo onMouseEnterEvent;
 		private Delegate realMouseEnterHandler;
-		private EventInfo onMouseLeaveEvent;
 		private Delegate realMouseLeaveHandler;
-		private MethodInfo destroyMethod;
-
-		internal Button(object realButton, Type iButtonType, Type functionVisibilityType) {
+
+		internal Button(object realButton, ToolbarTypes types) {
 			this.realButton = realButton;
-			this.functionVisibilityType = functionVisibilityType;
-
-			textProperty = iButtonType.GetProperty("Text", BindingFlags.Public | BindingFlags.Instance);
-			textColorProperty = iButtonType.GetProperty("TextColor", BindingFlags.Public | BindingFlags.Instance);
-			texturePathProperty = iButtonType.GetProperty("TexturePath", BindingFlags.Public | BindingFlags.Instance);
-			toolTipProperty = iButtonType.GetProperty("ToolTip", BindingFlags.Public | BindingFlags.Instance);
-			visibleProperty = iButtonType.GetProperty("Visible", BindingFlags.Public | BindingFlags.Instance);
-			visibilityProperty = iButtonType.GetProperty("Visibility", BindingFlags.Public | BindingFlags.Instance);
-			effectivelyVisibleProperty = iButtonType.GetProperty("EffectivelyVisible", BindingFlags.Public | BindingFlags.Instance);
-			enabledProperty = iButtonType.GetProperty("Enabled", BindingFlags.Public | BindingFlags.Instance);
-			importantProperty = iButtonType.GetProperty("Important", BindingFlags.Public | BindingFlags.Instance);
-			onClickEvent = iButtonType.GetEvent("OnClick", BindingFlags.Public | BindingFlags.Instance);
-			onMouseEnterEvent = iButtonType.GetEvent("OnMouseEnter", BindingFlags.Public | BindingFlags.Instance);
-			onMouseLeaveEvent = iButtonType.GetEvent("OnMouseLeave", BindingFlags.Public | BindingFlags.Instance);
-			destroyMethod = iButtonType.GetMethod("Destroy", BindingFlags.Public | BindingFlags.Instance);
-
-			realClickHandler = attachEventHandler(onClickEvent, "clicked", realButton);
-			realMouseEnterHandler = attachEventHandler(onMouseEnterEvent, "mouseEntered", realButton);
-			realMouseLeaveHandler = attachEventHandler(onMouseLeaveEvent, "mouseLeft", realButton);
+			this.types = types;
+
+			realClickHandler = attachEventHandler(types.button.onClickEvent, "clicked", realButton);
+			realMouseEnterHandler = attachEventHandler(types.button.onMouseEnterEvent, "mouseEntered", realButton);
+			realMouseLeaveHandler = attachEventHandler(types.button.onMouseLeaveEvent, "mouseLeft", realButton);
 		}
 
 		private Delegate attachEventHandler(EventInfo @event, string methodName, object realButton) {
 			MethodInfo method = GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
 			Delegate d = Delegate.CreateDelegate(@event.EventHandlerType, this, method);
-			@event.GetAddMethod().Invoke(realButton, new object[] { d });
+			@event.AddEventHandler(realButton, d);
 			return d;
 		}
 
 		public string Text {
 			set {
-				textProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (string) textProperty.GetValue(realButton, null);
+				types.button.textProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (string) types.button.textProperty.GetValue(realButton, null);
 			}
 		}
 
 		public Color TextColor {
 			set {
-				textColorProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (Color) textColorProperty.GetValue(realButton, null);
+				types.button.textColorProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (Color) types.button.textColorProperty.GetValue(realButton, null);
 			}
 		}
 
 		public string TexturePath {
 			set {
-				texturePathProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (string) texturePathProperty.GetValue(realButton, null);
+				types.button.texturePathProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (string) types.button.texturePathProperty.GetValue(realButton, null);
 			}
 		}
 
 		public string ToolTip {
 			set {
-				toolTipProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (string) toolTipProperty.GetValue(realButton, null);
+				types.button.toolTipProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (string) types.button.toolTipProperty.GetValue(realButton, null);
 			}
 		}
 
 		public bool Visible {
 			set {
-				visibleProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (bool) visibleProperty.GetValue(realButton, null);
+				types.button.visibleProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (bool) types.button.visibleProperty.GetValue(realButton, null);
 			}
 		}
 
 		public IVisibility Visibility {
 			set {
-				object functionVisibility = Activator.CreateInstance(functionVisibilityType, new object[] { new Func<bool>(() => value.Visible) });
-				visibilityProperty.SetValue(realButton, functionVisibility, null);
+				object functionVisibility = null;
+				if (value != null) {
+					functionVisibility = Activator.CreateInstance(types.functionVisibilityType, new object[] { new Func<bool>(() => value.Visible) });
+				}
+				types.button.visibilityProperty.SetValue(realButton, functionVisibility, null);
 				visibility_ = value;
 			}
 			get {
@@ -545,27 +610,45 @@
 
 		public bool EffectivelyVisible {
 			get {
-				return (bool) effectivelyVisibleProperty.GetValue(realButton, null);
+				return (bool) types.button.effectivelyVisibleProperty.GetValue(realButton, null);
 			}
 		}
 
 		public bool Enabled {
 			set {
-				enabledProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (bool) enabledProperty.GetValue(realButton, null);
+				types.button.enabledProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (bool) types.button.enabledProperty.GetValue(realButton, null);
 			}
 		}
 
 		public bool Important {
 			set {
-				importantProperty.SetValue(realButton, value, null);
-			}
-			get {
-				return (bool) importantProperty.GetValue(realButton, null);
-			}
-		}
+				types.button.importantProperty.SetValue(realButton, value, null);
+			}
+			get {
+				return (bool) types.button.importantProperty.GetValue(realButton, null);
+			}
+		}
+
+		public IDrawable Drawable {
+			set {
+				object functionDrawable = null;
+				if (value != null) {
+					functionDrawable = Activator.CreateInstance(types.functionDrawableType, new object[] {
+						new Action(() => value.Update()),
+						new Func<Vector2, Vector2>((pos) => value.Draw(pos))
+					});
+				}
+				types.button.drawableProperty.SetValue(realButton, functionDrawable, null);
+				drawable_ = value;
+			}
+			get {
+				return drawable_;
+			}
+		}
+		private IDrawable drawable_;
 
 		public event ClickHandler OnClick;
 
@@ -592,19 +675,15 @@
 		}
 
 		public void Destroy() {
-			detachEventHandler(onClickEvent, realClickHandler, realButton);
-			detachEventHandler(onMouseEnterEvent, realMouseEnterHandler, realButton);
-			detachEventHandler(onMouseLeaveEvent, realMouseLeaveHandler, realButton);
-
-			destroyMethod.Invoke(realButton, null);
+			detachEventHandler(types.button.onClickEvent, realClickHandler, realButton);
+			detachEventHandler(types.button.onMouseEnterEvent, realMouseEnterHandler, realButton);
+			detachEventHandler(types.button.onMouseLeaveEvent, realMouseLeaveHandler, realButton);
+
+			types.button.destroyMethod.Invoke(realButton, null);
 		}
 
 		private void detachEventHandler(EventInfo @event, Delegate d, object realButton) {
-			@event.GetRemoveMethod().Invoke(realButton, new object[] { d });
-		}
-
-		private Delegate createDelegate(Type eventHandlerType, string methodName) {
-			return Delegate.CreateDelegate(GetType(), GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance));
+			@event.RemoveEventHandler(realButton, d);
 		}
 	}
 
@@ -634,6 +713,81 @@
 		}
 	}
 
+	internal class ToolbarTypes {
+		internal readonly Type iToolbarManagerType;
+		internal readonly Type functionVisibilityType;
+		internal readonly Type functionDrawableType;
+		internal readonly ButtonTypes button;
+
+		internal ToolbarTypes() {
+			iToolbarManagerType = getType("Toolbar.IToolbarManager");
+			functionVisibilityType = getType("Toolbar.FunctionVisibility");
+			functionDrawableType = getType("Toolbar.FunctionDrawable");
+
+			Type iButtonType = getType("Toolbar.IButton");
+			button = new ButtonTypes(iButtonType);
+		}
+
+		internal static Type getType(string name) {
+			return AssemblyLoader.loadedAssemblies
+				.SelectMany(a => a.assembly.GetExportedTypes())
+				.SingleOrDefault(t => t.FullName == name);
+		}
+
+		internal static PropertyInfo getProperty(Type type, string name) {
+			return type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
+		}
+
+		internal static PropertyInfo getStaticProperty(Type type, string name) {
+			return type.GetProperty(name, BindingFlags.Public | BindingFlags.Static);
+		}
+
+		internal static EventInfo getEvent(Type type, string name) {
+			return type.GetEvent(name, BindingFlags.Public | BindingFlags.Instance);
+		}
+
+		internal static MethodInfo getMethod(Type type, string name) {
+			return type.GetMethod(name, BindingFlags.Public | BindingFlags.Instance);
+		}
+	}
+
+	internal class ButtonTypes {
+		internal readonly Type iButtonType;
+		internal readonly PropertyInfo textProperty;
+		internal readonly PropertyInfo textColorProperty;
+		internal readonly PropertyInfo texturePathProperty;
+		internal readonly PropertyInfo toolTipProperty;
+		internal readonly PropertyInfo visibleProperty;
+		internal readonly PropertyInfo visibilityProperty;
+		internal readonly PropertyInfo effectivelyVisibleProperty;
+		internal readonly PropertyInfo enabledProperty;
+		internal readonly PropertyInfo importantProperty;
+		internal readonly PropertyInfo drawableProperty;
+		internal readonly EventInfo onClickEvent;
+		internal readonly EventInfo onMouseEnterEvent;
+		internal readonly EventInfo onMouseLeaveEvent;
+		internal readonly MethodInfo destroyMethod;
+
+		internal ButtonTypes(Type iButtonType) {
+			this.iButtonType = iButtonType;
+
+			textProperty = ToolbarTypes.getProperty(iButtonType, "Text");
+			textColorProperty = ToolbarTypes.getProperty(iButtonType, "TextColor");
+			texturePathProperty = ToolbarTypes.getProperty(iButtonType, "TexturePath");
+			toolTipProperty = ToolbarTypes.getProperty(iButtonType, "ToolTip");
+			visibleProperty = ToolbarTypes.getProperty(iButtonType, "Visible");
+			visibilityProperty = ToolbarTypes.getProperty(iButtonType, "Visibility");
+			effectivelyVisibleProperty = ToolbarTypes.getProperty(iButtonType, "EffectivelyVisible");
+			enabledProperty = ToolbarTypes.getProperty(iButtonType, "Enabled");
+			importantProperty = ToolbarTypes.getProperty(iButtonType, "Important");
+			drawableProperty = ToolbarTypes.getProperty(iButtonType, "Drawable");
+			onClickEvent = ToolbarTypes.getEvent(iButtonType, "OnClick");
+			onMouseEnterEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseEnter");
+			onMouseLeaveEvent = ToolbarTypes.getEvent(iButtonType, "OnMouseLeave");
+			destroyMethod = ToolbarTypes.getMethod(iButtonType, "Destroy");
+		}
+	}
+
 	#endregion
 }