From eb40e9547d9823acd92998b2f31f43b3d5b48a6a Mon Sep 17 00:00:00 2001 From: Henry Bauer Date: Thu, 20 Feb 2020 16:41:42 -0600 Subject: [PATCH] Switch to ToolbarController, bump to 1.1 --- GameData/Undockinator.version | 29 +- Properties/AssemblyInfo.cs | 7 +- ToolbarWrapper.cs | 791 ---------------------------------- Undockinator.cs | 629 ++++++++++++--------------- Undockinator.csproj | 25 +- Undockinator.sln | 2 +- 6 files changed, 319 insertions(+), 1164 deletions(-) delete mode 100644 ToolbarWrapper.cs diff --git a/GameData/Undockinator.version b/GameData/Undockinator.version index 8b1317e..c3179dc 100644 --- a/GameData/Undockinator.version +++ b/GameData/Undockinator.version @@ -1,11 +1,20 @@ { -"NAME":"Undockinator", -"URL":"https://raw.githubusercontent.com/henrybauer/Undockinator/master/GameData/Undockinator.version", -"DOWNLOAD":"http://forum.kerbalspaceprogram.com/index.php?/topic/149144-12pre-the-undockinator-v01-undock-your-ships/", -"VERSION": { - "MAJOR":1,"MINOR":0,"PATCH":3,"BUILD":0 -}, -"KSP_VERSION": { - "MAJOR":1,"MINOR":7,"PATCH":3 -} -} + "NAME":"Undockinator", + "URL":"https://raw.githubusercontent.com/henrybauer/Undockinator/master/GameData/Undockinator.version", + "DOWNLOAD":"http://forum.kerbalspaceprogram.com/index.php?/topic/149144-12pre-the-undockinator-v01-undock-your-ships/", + "tags":[ + "plugin", + "convenience" + ], + "VERSION":{ + "MAJOR":1, + "MINOR":1, + "PATCH":0, + "BUILD":0 + }, + "KSP_VERSION_MIN":{ + "MAJOR":1, + "MINOR":9, + "PATCH":0 + } +} \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index bf738d3..c75eaf8 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -17,11 +17,14 @@ // The form "{Major}.{Minor}.*" will automatically update the build and revision, // and "{Major}.{Minor}.{Build}.*" will update just the revision. -[assembly: AssemblyVersion("1.0.3")] -[assembly: AssemblyFileVersion("1.0.3")] +[assembly: AssemblyVersion("1.1.0")] +[assembly: AssemblyFileVersion("1.1.0")] // The following attributes are used to specify the signing key for the assembly, // if desired. See the Mono documentation for more information about signing. //[assembly: AssemblyDelaySign(false)] //[assembly: AssemblyKeyFile("")] + +[assembly: KSPAssemblyDependency("ClickThroughBlocker", 1, 0)] +[assembly: KSPAssemblyDependency("ToolbarController", 1, 0)] \ No newline at end of file diff --git a/ToolbarWrapper.cs b/ToolbarWrapper.cs deleted file mode 100644 index 310cd47..0000000 --- a/ToolbarWrapper.cs +++ /dev/null @@ -1,791 +0,0 @@ -/* -Copyright (c) 2013-2016, Maik Schreiber -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -using System; -using System.Collections.Generic; -using System.Reflection; -using UnityEngine; - - -namespace Undockinator { - - - - /**********************************************************\ - * --- DO NOT EDIT BELOW THIS COMMENT --- * - * * - * This file contains classes and interfaces to use the * - * Toolbar Plugin without creating a hard dependency on it. * - * * - * There is nothing in this file that needs to be edited * - * by hand. * - * * - * --- DO NOT EDIT BELOW THIS COMMENT --- * - \**********************************************************/ - - - - /// - /// The global tool bar manager. - /// - public partial class ToolbarManager : IToolbarManager { - /// - /// Whether the Toolbar Plugin is available. - /// - public static bool ToolbarAvailable { - get { - if (toolbarAvailable == null) { - toolbarAvailable = Instance != null; - } - return (bool) toolbarAvailable; - } - } - - /// - /// The global tool bar manager instance. - /// - public static IToolbarManager Instance { - get { - if ((toolbarAvailable != false) && (instance_ == null)) { - Type type = ToolbarTypes.getType("Toolbar.ToolbarManager"); - if (type != null) { - object realToolbarManager = ToolbarTypes.getStaticProperty(type, "Instance").GetValue(null, null); - instance_ = new ToolbarManager(realToolbarManager); - } - } - return instance_; - } - } - } - - #region interfaces - - /// - /// A toolbar manager. - /// - public interface IToolbarManager { - /// - /// Adds a new button. - /// - /// - /// To replace an existing button, just add a new button using the old button's namespace and ID. - /// Note that the new button will inherit the screen position of the old button. - /// - /// The new button's namespace. This is usually the plugin's name. Must not include special characters like '.' - /// The new button's ID. This ID must be unique across all buttons in the namespace. Must not include special characters like '.' - /// The button created. - IButton add(string ns, string id); - } - - /// - /// Represents a clickable button. - /// - public interface IButton { - /// - /// The text displayed on the button. Set to null to hide text. - /// - /// - /// The text can be changed at any time to modify the button's appearance. Note that since this will also - /// modify the button's size, this feature should be used sparingly, if at all. - /// - /// - string Text { - set; - get; - } - - /// - /// The color the button text is displayed with. Defaults to Color.white. - /// - /// - /// The text color can be changed at any time to modify the button's appearance. - /// - Color TextColor { - set; - get; - } - - /// - /// The path of a texture file to display an icon on the button. Set to null to hide icon. - /// - /// - /// - /// A texture path on a button will have precedence over text. That is, if both text and texture path - /// have been set on a button, the button will show the texture, not the text. - /// - /// - /// The texture size must not exceed 24x24 pixels. - /// - /// - /// The texture path must be relative to the "GameData" directory, and must not specify a file name suffix. - /// Valid example: MyAddon/Textures/icon_mybutton - /// - /// - /// The texture path can be changed at any time to modify the button's appearance. - /// - /// - /// - string TexturePath { - set; - get; - } - - /// - /// The button's tool tip text. Set to null if no tool tip is desired. - /// - /// - /// Tool Tip Text Should Always Use Headline Style Like This. - /// - string ToolTip { - set; - get; - } - - /// - /// Whether this button is currently visible or not. Can be used in addition to or as a replacement for . - /// - /// - /// Setting this property to true does not affect the player's ability to hide the button using the configuration. - /// Conversely, setting this property to false does not enable the player to show the button using the configuration. - /// - bool Visible { - set; - get; - } - - /// - /// Determines this button's visibility. Can be used in addition to or as a replacement for . - /// - /// - /// The return value from IVisibility.Visible is subject to the same rules as outlined for - /// . - /// - IVisibility Visibility { - set; - get; - } - - /// - /// Whether this button is currently effectively visible or not. This is a combination of - /// and . - /// - /// - /// Note that the toolbar is not visible in certain game scenes, for example the loading screens. This property - /// does not reflect button invisibility in those scenes. In addition, this property does not reflect the - /// player's configuration of the button's visibility. - /// - bool EffectivelyVisible { - get; - } - - /// - /// Whether this button is currently enabled (clickable) or not. This does not affect the player's ability to - /// position the button on their toolbar. - /// - bool Enabled { - set; - get; - } - - /// - /// Whether this button is currently "important." Set to false to return to normal button behaviour. - /// - /// - /// - /// This can be used to temporarily force the button to be shown on screen regardless of the toolbar being - /// currently in auto-hidden mode. For example, a button that signals the arrival of a private message in - /// a chat room could mark itself as "important" as long as the message has not been read. - /// - /// - /// Setting this property does not change the appearance of the button. Use to - /// change the button's icon. - /// - /// - /// Setting this property to true does not affect the player's ability to hide the button using the - /// configuration. - /// - /// - /// This feature should be used only sparingly, if at all, since it forces the button to be displayed on - /// screen even when it normally wouldn't. - /// - /// - bool Important { - set; - get; - } - - /// - /// 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. - /// - IDrawable Drawable { - set; - get; - } - - /// - /// Event handler that can be registered with to receive "on click" events. - /// - /// - /// - /// IButton button = ... - /// button.OnClick += (e) => { - /// Debug.Log("button clicked, mouseButton: " + e.MouseButton); - /// }; - /// - /// - event ClickHandler OnClick; - - /// - /// Event handler that can be registered with to receive "on mouse enter" events. - /// - /// - /// - /// IButton button = ... - /// button.OnMouseEnter += (e) => { - /// Debug.Log("mouse entered button"); - /// }; - /// - /// - event MouseEnterHandler OnMouseEnter; - - /// - /// Event handler that can be registered with to receive "on mouse leave" events. - /// - /// - /// - /// IButton button = ... - /// button.OnMouseLeave += (e) => { - /// Debug.Log("mouse left button"); - /// }; - /// - /// - event MouseLeaveHandler OnMouseLeave; - - /// - /// Permanently destroys this button so that it is no longer displayed. - /// Should be used when a plugin is stopped to remove leftover buttons. - /// - void Destroy(); - } - - /// - /// A drawable that is tied to a particular button. This can be anything from a popup menu - /// to an informational window. - /// - public interface IDrawable { - /// - /// Update any information. This is called once per frame. - /// - void Update(); - - /// - /// Draws GUI widgets for this drawable. This is the equivalent to the OnGUI() message in - /// . - /// - /// - /// The drawable will be positioned near its parent toolbar according to the drawable's current - /// width/height. - /// - /// The left/top position of where to draw this drawable. - /// The current width/height of this drawable. - Vector2 Draw(Vector2 position); - } - - #endregion - - #region events - - /// - /// Event describing a click on a button. - /// - public partial class ClickEvent : EventArgs { - /// - /// The button that has been clicked. - /// - public readonly IButton Button; - - /// - /// The mouse button which the button was clicked with. - /// - /// - /// Is 0 for left mouse button, 1 for right mouse button, and 2 for middle mouse button. - /// - public readonly int MouseButton; - } - - /// - /// An event handler that is invoked whenever a button has been clicked. - /// - /// An event describing the button click. - public delegate void ClickHandler(ClickEvent e); - - /// - /// Event describing the mouse pointer moving about a button. - /// - public abstract partial class MouseMoveEvent { - /// - /// The button in question. - /// - public readonly IButton button; - } - - /// - /// Event describing the mouse pointer entering a button's area. - /// - public partial class MouseEnterEvent : MouseMoveEvent { - } - - /// - /// Event describing the mouse pointer leaving a button's area. - /// - public partial class MouseLeaveEvent : MouseMoveEvent { - } - - /// - /// An event handler that is invoked whenever the mouse pointer enters a button's area. - /// - /// An event describing the mouse pointer entering. - public delegate void MouseEnterHandler(MouseEnterEvent e); - - /// - /// An event handler that is invoked whenever the mouse pointer leaves a button's area. - /// - /// An event describing the mouse pointer leaving. - public delegate void MouseLeaveHandler(MouseLeaveEvent e); - - #endregion - - #region visibility - - /// - /// Determines visibility of a button. - /// - /// - public interface IVisibility { - /// - /// Whether a button is currently visible or not. - /// - /// - bool Visible { - get; - } - } - - /// - /// Determines visibility of a button in relation to the currently running game scene. - /// - /// - /// - /// IButton button = ... - /// button.Visibility = new GameScenesVisibility(GameScenes.EDITOR, GameScenes.FLIGHT); - /// - /// - /// - public class GameScenesVisibility : IVisibility { - public bool Visible { - get { - return (bool) visibleProperty.GetValue(realGameScenesVisibility, null); - } - } - - private object realGameScenesVisibility; - private PropertyInfo visibleProperty; - - public GameScenesVisibility(params GameScenes[] gameScenes) { - Type gameScenesVisibilityType = ToolbarTypes.getType("Toolbar.GameScenesVisibility"); - realGameScenesVisibility = Activator.CreateInstance(gameScenesVisibilityType, new object[] { gameScenes }); - visibleProperty = ToolbarTypes.getProperty(gameScenesVisibilityType, "Visible"); - } - } - - #endregion - - #region drawable - - /// - /// A drawable that draws a popup menu. - /// - public partial class PopupMenuDrawable : IDrawable { - /// - /// Event handler that can be registered with to receive "any menu option clicked" events. - /// - 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 }); - } - - /// - /// Adds a new option to the popup menu. - /// - /// The text of the option. - /// A button that can be used to register clicks on the menu option. - public IButton AddOption(string text) { - object realButton = addOptionMethod.Invoke(realPopupMenuDrawable, new object[] { text }); - return new Button(realButton, new ToolbarTypes()); - } - - /// - /// Adds a separator to the popup menu. - /// - public void AddSeparator() { - addSeparatorMethod.Invoke(realPopupMenuDrawable, null); - } - - /// - /// Destroys this drawable. This must always be called before disposing of this drawable. - /// - public void Destroy() { - destroyMethod.Invoke(realPopupMenuDrawable, null); - } - } - - #endregion - - #region private implementations - - public partial class ToolbarManager : IToolbarManager { - private static bool? toolbarAvailable = null; - private static IToolbarManager instance_; - - private object realToolbarManager; - private MethodInfo addMethod; - private Dictionary buttons = new Dictionary(); - private ToolbarTypes types = new ToolbarTypes(); - - private ToolbarManager(object realToolbarManager) { - this.realToolbarManager = realToolbarManager; - - 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, types); - buttons.Add(realButton, button); - return button; - } - } - - internal class Button : IButton { - private object realButton; - private ToolbarTypes types; - private Delegate realClickHandler; - private Delegate realMouseEnterHandler; - private Delegate realMouseLeaveHandler; - - internal Button(object realButton, ToolbarTypes types) { - this.realButton = 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.AddEventHandler(realButton, d); - return d; - } - - public string Text { - set { - types.button.textProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.textProperty.GetValue(realButton, null); - } - } - - public Color TextColor { - set { - types.button.textColorProperty.SetValue(realButton, value, null); - } - get { - return (Color) types.button.textColorProperty.GetValue(realButton, null); - } - } - - public string TexturePath { - set { - types.button.texturePathProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.texturePathProperty.GetValue(realButton, null); - } - } - - public string ToolTip { - set { - types.button.toolTipProperty.SetValue(realButton, value, null); - } - get { - return (string) types.button.toolTipProperty.GetValue(realButton, null); - } - } - - public bool Visible { - set { - types.button.visibleProperty.SetValue(realButton, value, null); - } - get { - return (bool) types.button.visibleProperty.GetValue(realButton, null); - } - } - - public IVisibility Visibility { - set { - object functionVisibility = null; - if (value != null) { - functionVisibility = Activator.CreateInstance(types.functionVisibilityType, new object[] { new Func(() => value.Visible) }); - } - types.button.visibilityProperty.SetValue(realButton, functionVisibility, null); - visibility_ = value; - } - get { - return visibility_; - } - } - private IVisibility visibility_; - - public bool EffectivelyVisible { - get { - return (bool) types.button.effectivelyVisibleProperty.GetValue(realButton, null); - } - } - - public bool Enabled { - set { - types.button.enabledProperty.SetValue(realButton, value, null); - } - get { - return (bool) types.button.enabledProperty.GetValue(realButton, null); - } - } - - public bool Important { - set { - 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((pos) => value.Draw(pos)) - }); - } - types.button.drawableProperty.SetValue(realButton, functionDrawable, null); - drawable_ = value; - } - get { - return drawable_; - } - } - private IDrawable drawable_; - - public event ClickHandler OnClick; - - private void clicked(object realEvent) { - if (OnClick != null) { - OnClick(new ClickEvent(realEvent, this)); - } - } - - public event MouseEnterHandler OnMouseEnter; - - private void mouseEntered(object realEvent) { - if (OnMouseEnter != null) { - OnMouseEnter(new MouseEnterEvent(this)); - } - } - - public event MouseLeaveHandler OnMouseLeave; - - private void mouseLeft(object realEvent) { - if (OnMouseLeave != null) { - OnMouseLeave(new MouseLeaveEvent(this)); - } - } - - public void Destroy() { - 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.RemoveEventHandler(realButton, d); - } - } - - public partial class ClickEvent : EventArgs { - internal ClickEvent(object realEvent, IButton button) { - Type type = realEvent.GetType(); - Button = button; - MouseButton = (int) type.GetField("MouseButton", BindingFlags.Public | BindingFlags.Instance).GetValue(realEvent); - } - } - - public abstract partial class MouseMoveEvent : EventArgs { - internal MouseMoveEvent(IButton button) { - this.button = button; - } - } - - public partial class MouseEnterEvent : MouseMoveEvent { - internal MouseEnterEvent(IButton button) - : base(button) { - } - } - - public partial class MouseLeaveEvent : MouseMoveEvent { - internal MouseLeaveEvent(IButton button) - : base(button) { - } - } - - 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) { - Type type = null; - AssemblyLoader.loadedAssemblies.TypeOperation(t => { - if (t.FullName == name) { - type = t; - } - }); - return type; - } - - 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 -} diff --git a/Undockinator.cs b/Undockinator.cs index bbfe569..5573fb5 100644 --- a/Undockinator.cs +++ b/Undockinator.cs @@ -7,60 +7,68 @@ #if DEBUG using KramaxReloadExtensions; #endif +using ToolbarControl_NS; +using ClickThroughFix; namespace Undockinator { - [KSPAddon(KSPAddon.Startup.Flight, false)] + [KSPAddon(KSPAddon.Startup.MainMenu, true)] + public class RegisterToolbar : MonoBehaviour + { + void Start() + { + ToolbarControl.RegisterMod(Undockinator.MODID, Undockinator.MODNAME); + } + } + + [KSPAddon(KSPAddon.Startup.Flight, false)] #if DEBUG public class Undockinator : ReloadableMonoBehaviour #else - public class Undockinator : MonoBehaviour + public class Undockinator : MonoBehaviour #endif - { - // toolbar - private bool useBlizzy = false; - private bool blizzyAvailable = false; - private IButton blizzyButton; - private Texture2D appTexture = null; - private bool setupApp = false; - private ApplicationLauncherButton appButton = null; - - // GUI + { + // toolbar + internal const string MODID = "Undockinator"; + internal const string MODNAME = "Undockinator"; + ToolbarControl toolbarControl; + + // GUI #if DEBUG bool visible = true; #else - bool visible = false; + bool visible = false; #endif - string versionString = null; - private Rect windowRect = new Rect(200, 200, 1, 1); - private int windowID = new System.Random().Next(int.MaxValue); - GUIStyle nonbreakingLabelStyle; - static float maxPartNameWidth = -1f; - static float maxShipNameWidth = -1f; - Part highlightPart = null; + string versionString = null; + private Rect windowRect = new Rect(200, 200, 1, 1); + private int windowID = new System.Random().Next(int.MaxValue); + GUIStyle nonbreakingLabelStyle; + static float maxPartNameWidth = -1f; + static float maxShipNameWidth = -1f; + Part highlightPart = null; Part highlightPartnerPart = null; public Vector2 scrollPosition; - private bool showRename = false; - private UndockablePort renamePort; - private string renameName = null; + private bool showRename = false; + private UndockablePort renamePort; + private string renameName = null; FlightCamera flightCamera; float pivotTranslateSharpness = 0; // ship survey private List portList = new List(); - Vessel currentVessel; + Vessel currentVessel; - class UndockablePort - { - private ModuleDockingNode pm; + class UndockablePort + { + private ModuleDockingNode pm; private ModuleDockingNode partnerPM; private ModuleGrappleNode gm; public Part part; - public Part partner; - public string portName; - public string shipName; - public bool dpai; - private PartModule dpaiModule; + public Part partner; + public string portName; + public string shipName; + public bool dpai; + private PartModule dpaiModule; public void rename(string newName) { @@ -71,10 +79,12 @@ public void rename(string newName) public void undock() { - if (pm==null){ + if (pm == null) + { gm.Decouple(); } - else { + else + { if (shipName == "PreAttached") { pm.Decouple(); @@ -87,7 +97,7 @@ public void undock() } public UndockablePort(PartModule newPartModule) - { + { part = newPartModule.part; portName = part.partInfo.title; @@ -129,13 +139,13 @@ public UndockablePort(PartModule newPartModule) shipName = "???"; } } - + } - - // get DPAI module, extract name (if any) - dpai = false; - dpaiModule = null; + + // get DPAI module, extract name (if any) + dpai = false; + dpaiModule = null; if (pm != null) // DPAI only supports ModuleDockingNode, not ModuleGrappleNode { string dpaiName = null; @@ -158,45 +168,45 @@ public UndockablePort(PartModule newPartModule) } } - // Shrink the part names if they're using the default ones - switch (portName) - { - case "Clamp-O-Tron Docking Port": - portName = "Clamp-O-Tron"; break; - case "Clamp-O-Tron Docking Port Jr.": - portName = "Clamp-O-Tron Jr"; break; - case "Clamp-O-Tron Docking Port Sr.": - portName = "Clamp-O-Tron Sr"; break; - case "Clamp-O-Tron Shielded Docking Port": - portName = "Clamp-O-Tron Shielded"; break; - } - } - } - - public void scanVessel(Vessel gameEventVessel = null) - { + // Shrink the part names if they're using the default ones + switch (portName) + { + case "Clamp-O-Tron Docking Port": + portName = "Clamp-O-Tron"; break; + case "Clamp-O-Tron Docking Port Jr.": + portName = "Clamp-O-Tron Jr"; break; + case "Clamp-O-Tron Docking Port Sr.": + portName = "Clamp-O-Tron Sr"; break; + case "Clamp-O-Tron Shielded Docking Port": + portName = "Clamp-O-Tron Shielded"; break; + } + } + } + + public void scanVessel(Vessel gameEventVessel = null) + { #if DEBUG UDprint("Scanning vessel for undockable parts"); #endif resetHighLight(); currentVessel = FlightGlobals.ActiveVessel; - portList.Clear(); - maxShipNameWidth = -1f; - maxPartNameWidth = -1f; - scrollPosition = new Vector2(0, 0); - ModuleDockingNode pm; + portList.Clear(); + maxShipNameWidth = -1f; + maxPartNameWidth = -1f; + scrollPosition = new Vector2(0, 0); + ModuleDockingNode pm; ModuleGrappleNode gm; - // Gather docking ports - for (int i = currentVessel.Parts.Count - 1; i >= 0; --i) - { - for (int j = currentVessel.parts[i].Modules.Count - 1; j >= 0; --j) - { - if (currentVessel.parts[i].Modules[j].moduleName == "ModuleDockingNode") - { - pm = (ModuleDockingNode)currentVessel.parts[i].Modules[j]; - if (pm.state.StartsWith("Docked") || pm.state.StartsWith("PreAttached")) - { + // Gather docking ports + for (int i = currentVessel.Parts.Count - 1; i >= 0; --i) + { + for (int j = currentVessel.parts[i].Modules.Count - 1; j >= 0; --j) + { + if (currentVessel.parts[i].Modules[j].moduleName == "ModuleDockingNode") + { + pm = (ModuleDockingNode)currentVessel.parts[i].Modules[j]; + if (pm.state.StartsWith("Docked") || pm.state.StartsWith("PreAttached")) + { Boolean uniquePort = true; for (int k = portList.Count - 1; k >= 0; --k) { @@ -210,131 +220,90 @@ public void scanVessel(Vessel gameEventVessel = null) { portList.Add(new UndockablePort(currentVessel.parts[i].Modules[j])); } - } - } + } + } if (currentVessel.parts[i].Modules[j].moduleName == "ModuleGrappleNode") { gm = (ModuleGrappleNode)currentVessel.parts[i].Modules[j]; - print ("Grapple: " + gm.state.ToString()); + print("Grapple: " + gm.state.ToString()); if (gm.state.StartsWith("Grappled")) { portList.Add(new UndockablePort(currentVessel.parts[i].Modules[j])); } } - } - } - } - - public void getMaxWidths() - { - GUIContent g; - float width; - - maxPartNameWidth = 0f; - maxShipNameWidth = 0f; - - for (int i = portList.Count - 1; i >= 0; --i) - { - g = new GUIContent(portList[i].portName); - //width = nonbreakingLabelStyle.CalcSize(g).x; - width = GUI.skin.GetStyle("Button").CalcSize(g).x; - if (width > maxPartNameWidth) { maxPartNameWidth = width; }; - - g = new GUIContent(portList[i].shipName); - //width = nonbreakingLabelStyle.CalcSize(g).x; - width = GUI.skin.GetStyle("Button").CalcSize(g).x; - if (width > maxShipNameWidth) { maxShipNameWidth = width; }; - } - } - - public void Awake() - { - if (ToolbarManager.ToolbarAvailable) - { - UDprint("Blizzy's toolbar available"); - blizzyButton = ToolbarManager.Instance.add("Undockinator", "UndockinatorButton"); - blizzyButton.TexturePath = "Undockinator/undockinator"; - blizzyButton.ToolTip = "Undockinator"; - blizzyButton.Visibility = new GameScenesVisibility(GameScenes.FLIGHT); - blizzyButton.OnClick += (e) => - { - buttonPressed(); - }; - blizzyButton.Visible = useBlizzy; - blizzyAvailable = true; - } - else - { - UDprint("Blizzy's toolbar not available, using stock toolbar"); - blizzyButton = null; - useBlizzy = false; - blizzyAvailable = false; - } - - //setup app launcher after toolbar in case useBlizzy=true but user removed toolbar - GameEvents.onGUIApplicationLauncherReady.Add(setupAppButton); - GameEvents.onGUIApplicationLauncherUnreadifying.Add(cleanUpAppButton); - - -#if DEBUG - // don't load configs because KramaxReload screws up PluginConfiguration -#else - UDprint("Loading config values"); - PluginConfiguration config = PluginConfiguration.CreateForType(); - config.load(); - useBlizzy = config.GetValue("useBlizzy"); - windowRect.x = (float)config.GetValue("windowRectX"); - windowRect.y = (float)config.GetValue("windowRectY"); - if ((windowRect.x == 0) && (windowRect.y == 0)) - { - windowRect.x = Screen.width * 0.35f; - windowRect.y = Screen.height * 0.1f; - } -#endif - } + } + } + } - public void cleanUpAppButton(GameScenes data) + public void getMaxWidths() { - cleanUpAppButton(); + GUIContent g; + float width; + + maxPartNameWidth = 0f; + maxShipNameWidth = 0f; + + for (int i = portList.Count - 1; i >= 0; --i) + { + g = new GUIContent(portList[i].portName); + //width = nonbreakingLabelStyle.CalcSize(g).x; + width = GUI.skin.GetStyle("Button").CalcSize(g).x; + if (width > maxPartNameWidth) { maxPartNameWidth = width; }; + + g = new GUIContent(portList[i].shipName); + //width = nonbreakingLabelStyle.CalcSize(g).x; + width = GUI.skin.GetStyle("Button").CalcSize(g).x; + if (width > maxShipNameWidth) { maxShipNameWidth = width; }; + } } - public void cleanUpAppButton() + + public void Awake() { - if (appButton != null) + +#if DEBUG + // don't load configs because KramaxReload screws up PluginConfiguration +#else + UDprint("Loading config values"); + PluginConfiguration config = PluginConfiguration.CreateForType(); + config.load(); + windowRect.x = (float)config.GetValue("windowRectX"); + windowRect.y = (float)config.GetValue("windowRectY"); + if ((windowRect.x == 0) && (windowRect.y == 0)) { - GameEvents.onGUIApplicationLauncherReady.Remove(setupAppButton); - ApplicationLauncher.Instance.RemoveModApplication(appButton); - appButton = null; - setupApp = false; + windowRect.x = Screen.width * 0.35f; + windowRect.y = Screen.height * 0.1f; } +#endif } + public void OnDestroy() - { - cleanUpAppButton(); + { + toolbarControl.OnDestroy(); + Destroy(toolbarControl); #if DEBUG // don't save configs because KramaxReload screws up PluginConfiguration #else - UDprint("Saving config values"); - PluginConfiguration config = PluginConfiguration.CreateForType(); - config.SetValue("useBlizzy", useBlizzy); - config.SetValue("windowRectX", (int)windowRect.x); - config.SetValue("windowRectY", (int)windowRect.y); - config.save(); + UDprint("Saving config values"); + PluginConfiguration config = PluginConfiguration.CreateForType(); + config.SetValue("windowRectX", (int)windowRect.x); + config.SetValue("windowRectY", (int)windowRect.y); + config.save(); #endif - } - - public void OnGUI() - { - if (visible) - { - if (maxShipNameWidth == -1) - { - getMaxWidths(); - } - windowRect = GUILayout.Window(windowID, clampToScreen(windowRect), OnWindow, "The Undockinator " + versionString, GUILayout.MinWidth(300)); - } - } + } + + public void OnGUI() + { + if (visible) + { + if (maxShipNameWidth == -1) + { + getMaxWidths(); + } + windowRect = ClickThruBlocker.GUILayoutWindow(windowID, clampToScreen(windowRect), OnWindow, "The Undockinator " + versionString, GUILayout.MinWidth(300)); + } + } public void resetHighLight() { @@ -357,96 +326,79 @@ public void resetCamera() } public void OnWindow(int windowID) - { - //GUILayout.BeginHorizontal(); - //GUILayout.Label(maxPartNameWidth.ToString() + "/"+maxShipNameWidth.ToString()); - //GUILayout.EndHorizontal(); - - if (blizzyAvailable) - { - GUILayout.BeginHorizontal(); - useBlizzy = GUILayout.Toggle(useBlizzy, "Use Blizzy's toolbar"); - GUILayout.EndHorizontal(); - if (useBlizzy) - { - appButton.VisibleInScenes = ApplicationLauncher.AppScenes.NEVER; - } - else { - appButton.VisibleInScenes = ApplicationLauncher.AppScenes.FLIGHT; - } - blizzyButton.Visible = useBlizzy; - } - if (portList.Count == 0) - { - GUILayout.BeginHorizontal(); - GUILayout.Label("No docked docking ports found"); - GUILayout.EndHorizontal(); - } - else if (showRename) - { - GUILayout.BeginHorizontal(); - GUILayout.Label("Rename port: "); - renameName = GUILayout.TextField(renameName); - GUILayout.EndHorizontal(); - - GUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - if (GUILayout.Button("OK")) - { - showRename = false; + { + + if (portList.Count == 0) + { + GUILayout.BeginHorizontal(); + GUILayout.Label("No docked docking ports found"); + GUILayout.EndHorizontal(); + } + else if (showRename) + { + GUILayout.BeginHorizontal(); + GUILayout.Label("Rename port: "); + renameName = GUILayout.TextField(renameName); + GUILayout.EndHorizontal(); + + GUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("OK")) + { + showRename = false; renamePort.rename(renameName); scanVessel(); - } - GUILayout.FlexibleSpace(); - if (GUILayout.Button("Cancel")) - { - showRename = false; - } - GUILayout.FlexibleSpace(); - GUILayout.EndHorizontal(); - } - else - { - scrollPosition = GUILayout.BeginScrollView(scrollPosition, - GUILayout.Width(maxPartNameWidth + maxShipNameWidth + 30), - GUILayout.Height(Math.Min(400, (portList.Count+1) * 40))); - GUILayout.BeginVertical(); - GUILayout.BeginHorizontal(); - GUILayout.Label("Part name", GUILayout.Width(maxPartNameWidth)); - GUILayout.Label("Undock", GUILayout.Width(maxShipNameWidth)); - GUILayout.EndHorizontal(); - for (int i = portList.Count - 1; i >= 0; --i) - { - GUILayout.BeginHorizontal(); - if (portList[i].dpai) - { - if (GUILayout.Button(portList[i].portName, GUILayout.Width(maxPartNameWidth))) - { - UDprint("Showing rename window"); - showRename = true; - renameName = portList[i].portName; - renamePort = portList[i]; - } - } - else - { - GUILayout.Label(portList[i].portName, GUILayout.Width(maxPartNameWidth)); - } - if (GUILayout.Button(portList[i].shipName, GUILayout.Width(maxShipNameWidth))) - { + } + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Cancel")) + { + showRename = false; + } + GUILayout.FlexibleSpace(); + GUILayout.EndHorizontal(); + } + else + { + scrollPosition = GUILayout.BeginScrollView(scrollPosition, + GUILayout.Width(maxPartNameWidth + maxShipNameWidth + 30), + GUILayout.Height(Math.Min(400, (portList.Count + 1) * 40))); + GUILayout.BeginVertical(); + GUILayout.BeginHorizontal(); + GUILayout.Label("Part name", GUILayout.Width(maxPartNameWidth)); + GUILayout.Label("Undock", GUILayout.Width(maxShipNameWidth)); + GUILayout.EndHorizontal(); + for (int i = portList.Count - 1; i >= 0; --i) + { + GUILayout.BeginHorizontal(); + if (portList[i].dpai) + { + if (GUILayout.Button(portList[i].portName, GUILayout.Width(maxPartNameWidth))) + { + UDprint("Showing rename window"); + showRename = true; + renameName = portList[i].portName; + renamePort = portList[i]; + } + } + else + { + GUILayout.Label(portList[i].portName, GUILayout.Width(maxPartNameWidth)); + } + if (GUILayout.Button(portList[i].shipName, GUILayout.Width(maxShipNameWidth))) + { resetCamera(); resetHighLight(); portList[i].undock(); - visible = false; - } - GUILayout.EndHorizontal(); - - if (Event.current.type == EventType.Repaint && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) - { - if (highlightPart != null && highlightPart.HighlightActive) - { - highlightPart.SetHighlightDefault(); - } + visible = false; + } + GUILayout.EndHorizontal(); + + if (Event.current.type == EventType.Repaint && GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition)) + { + if (highlightPart != null && highlightPart.HighlightActive) + { + highlightPart.SetHighlightDefault(); + } if (highlightPartnerPart != null && highlightPartnerPart.HighlightActive) { highlightPartnerPart.SetHighlightDefault(); @@ -459,12 +411,12 @@ public void OnWindow(int windowID) highlightPartnerPart = portList[i].partner; if (!highlightPart.HighlightActive) - { - highlightPart.SetHighlight(true, false); - highlightPart.highlightType = Part.HighlightType.AlwaysOn; - highlightPart.SetHighlightColor(Color.yellow); - highlightPart.highlighter.OccluderOn(); - } + { + highlightPart.SetHighlight(true, false); + highlightPart.highlightType = Part.HighlightType.AlwaysOn; + highlightPart.SetHighlightColor(Color.yellow); + highlightPart.highlighter.OccluderOn(); + } if (highlightPartnerPart != null) { if (!highlightPartnerPart.HighlightActive) @@ -477,20 +429,20 @@ public void OnWindow(int windowID) } } - //if ((i % 2 == 0) && (i > 0)) - //{ - // GUILayout.Space(10); - //} - } - GUILayout.EndVertical(); - GUILayout.EndScrollView(); - } - - GUI.DragWindow(); - } - - public void buttonPressed() - { + //if ((i % 2 == 0) && (i > 0)) + //{ + // GUILayout.Space(10); + //} + } + GUILayout.EndVertical(); + GUILayout.EndScrollView(); + } + + GUI.DragWindow(); + } + + public void buttonPressed() + { if (visible) { resetCamera(); @@ -500,87 +452,60 @@ public void buttonPressed() { scanVessel(); } - visible = !visible; - } - - public void doNothing() - { - } + visible = !visible; + } - public void setupAppButton() + public void doNothing() { - UDprint("setupAppButton"); - if (ApplicationLauncher.Ready) - if (setupApp) - { - UDprint("already set up"); - cleanUpAppButton(); - setupApp = false; - } - else - { - setupApp = true; - ApplicationLauncher appinstance = ApplicationLauncher.Instance; - UDprint("Setting up AppLauncher Button"); - appTexture = loadTexture("Undockinator/undockinator-app"); - appButton = appinstance.AddModApplication(buttonPressed, buttonPressed, doNothing, doNothing, doNothing, doNothing, ApplicationLauncher.AppScenes.NEVER, appTexture); - if (useBlizzy) - { - appButton.VisibleInScenes = ApplicationLauncher.AppScenes.NEVER; - } - else - { - appButton.VisibleInScenes = ApplicationLauncher.AppScenes.FLIGHT; - } - } - else - { - UDprint("ApplicationLauncher.Ready is false"); - } - if (blizzyButton != null) - { - blizzyButton.Visible = useBlizzy; - } } - public void Start() - { - GameEvents.onVesselChange.Add(scanVessel); - // onVesselChange - switching between vessels with [ or ] keys + public void Start() + { + GameEvents.onVesselChange.Add(scanVessel); + // onVesselChange - switching between vessels with [ or ] keys - GameEvents.onVesselStandardModification.Add(scanVessel); - // onVesselStandardModification collects various vessel events and fires them off with a single one. - // Specifically - onPartAttach,onPartRemove,onPartCouple,onPartDie,onPartUndock,onVesselWasModified,onVesselPartCountChanged + GameEvents.onVesselStandardModification.Add(scanVessel); + // onVesselStandardModification collects various vessel events and fires them off with a single one. + // Specifically - onPartAttach,onPartRemove,onPartCouple,onPartDie,onPartUndock,onVesselWasModified,onVesselPartCountChanged - versionString = Assembly.GetCallingAssembly().GetName().Version.ToString(); + versionString = Assembly.GetCallingAssembly().GetName().Version.ToString(); - nonbreakingLabelStyle = new GUIStyle(); - nonbreakingLabelStyle.wordWrap = false; - nonbreakingLabelStyle.normal.textColor = Color.white; + nonbreakingLabelStyle = new GUIStyle(); + nonbreakingLabelStyle.wordWrap = false; + nonbreakingLabelStyle.normal.textColor = Color.white; flightCamera = FlightCamera.fetch; pivotTranslateSharpness = flightCamera.pivotTranslateSharpness; + + toolbarControl = gameObject.AddComponent(); + toolbarControl.AddToAllToolbars(buttonPressed, buttonPressed, + ApplicationLauncher.AppScenes.FLIGHT, + MODID, + "UndockinatorButton", + "Undockinator/undockinator-app", + "Undockinator/undockinator", + MODNAME + ); + } + + public static void UDprint(string taco) + { + print("[Undockinator] " + taco); } - public static void UDprint(string taco) - { - print("[Undockinator] " + taco); - } - - private static Texture2D loadTexture(string path) - { - UDprint("loading texture: " + path); - return GameDatabase.Instance.GetTexture(path, false); - } - - private static Rect clampToScreen(Rect rect) - { - rect.width = Mathf.Clamp(rect.width, 0, Screen.width); - rect.height = Mathf.Clamp(rect.height, 0, Screen.height); - rect.x = Mathf.Clamp(rect.x, 0, Screen.width - rect.width); - rect.y = Mathf.Clamp(rect.y, 0, Screen.height - rect.height); - return rect; - } - } - -} + private static Texture2D loadTexture(string path) + { + UDprint("loading texture: " + path); + return GameDatabase.Instance.GetTexture(path, false); + } + + private static Rect clampToScreen(Rect rect) + { + rect.width = Mathf.Clamp(rect.width, 0, Screen.width); + rect.height = Mathf.Clamp(rect.height, 0, Screen.height); + rect.x = Mathf.Clamp(rect.x, 0, Screen.width - rect.width); + rect.y = Mathf.Clamp(rect.y, 0, Screen.height - rect.height); + return rect; + } + } +} \ No newline at end of file diff --git a/Undockinator.csproj b/Undockinator.csproj index 03e0dcd..16364e0 100644 --- a/Undockinator.csproj +++ b/Undockinator.csproj @@ -10,7 +10,7 @@ v3.5 512 - 1.0.3 + 1.1.0 true @@ -33,12 +33,6 @@ Undockinator - - - - - - ..\Managed\Assembly-CSharp.dll False @@ -51,6 +45,22 @@ ..\Managed\UnityEngine.UI.dll False + + ..\Kerbal Space Program\GameData\001_ToolbarControl\Plugins\ToolbarControl.dll + False + + + ..\Kerbal Space Program\GameData\000_ClickThroughBlocker\Plugins\ClickThroughBlocker.dll + False + + + ..\Kerbal Space Program\KSP.app\Contents\Resources\Data\Managed\UnityEngine.CoreModule.dll + False + + + ..\Kerbal Space Program\KSP.app\Contents\Resources\Data\Managed\UnityEngine.IMGUIModule.dll + False + @@ -60,7 +70,6 @@ - diff --git a/Undockinator.sln b/Undockinator.sln index dc72e50..6901a7e 100644 --- a/Undockinator.sln +++ b/Undockinator.sln @@ -20,6 +20,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution - version = 1.0.3 + version = 1.1.0 EndGlobalSection EndGlobal