diff --git a/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.dll b/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.dll index 0f74c7c..4d0f6c3 100644 Binary files a/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.dll and b/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.dll differ diff --git a/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.version b/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.version index 7c1e701..b017916 100644 --- a/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.version +++ b/GameData/CriticalTemperatureGauge/Plugins/CriticalTemperatureGauge.version @@ -13,7 +13,7 @@ "MAJOR": 1, "MINOR": 1, "PATCH": 3, - "BUILD": 3 + "BUILD": 4 }, "KSP_VERSION": { diff --git a/GameData/CriticalTemperatureGauge/Textures/AppLauncherButton.png b/GameData/CriticalTemperatureGauge/Textures/AppLauncherButton.png new file mode 100644 index 0000000..b5258a0 Binary files /dev/null and b/GameData/CriticalTemperatureGauge/Textures/AppLauncherButton.png differ diff --git a/GameData/CriticalTemperatureGauge/Textures/BizzysToolbarButton.png b/GameData/CriticalTemperatureGauge/Textures/BizzysToolbarButton.png new file mode 100644 index 0000000..adbdea1 Binary files /dev/null and b/GameData/CriticalTemperatureGauge/Textures/BizzysToolbarButton.png differ diff --git a/GameData/CriticalTemperatureGauge/Textures/ToolbarButton.png b/GameData/CriticalTemperatureGauge/Textures/ToolbarButton.png deleted file mode 100644 index 6129240..0000000 Binary files a/GameData/CriticalTemperatureGauge/Textures/ToolbarButton.png and /dev/null differ diff --git a/src/CriticalTemperatureGauge/AppLauncher.cs b/src/CriticalTemperatureGauge/AppLauncher.cs new file mode 100644 index 0000000..833eaf7 --- /dev/null +++ b/src/CriticalTemperatureGauge/AppLauncher.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using KSP.UI.Screens; +using UnityEngine; + +namespace CriticalTemperatureGauge +{ + /// + /// Class that adds the AppLauncher button. + /// + [KSPAddon(KSPAddon.Startup.Flight, false)] + public class AppLauncher : MonoBehaviour + { + // Resources + static readonly Texture2D AppLauncherButtonTexture = + GameDatabase.Instance.GetTexture(Static.TexturePath + "AppLauncherButton", false); + + ApplicationLauncherButton _appLauncherButton; + readonly SettingsWindow _settingsWindow = new SettingsWindow(); + + public void Update() + { + if(_appLauncherButton != null) + _appLauncherButton.VisibleInScenes = Static.Settings.ShowAppLauncherButton + ? ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW + : ApplicationLauncher.AppScenes.NEVER; + } + + public bool ButtonState + { + get + { + return _settingsWindow.IsLogicallyVisible; + } + set + { + if(value) + _appLauncherButton?.SetTrue(); + else + _appLauncherButton?.SetFalse(); + } + } + + // KSP events: + + public void Start() + { + OnGUIApplicationLauncherReady(); + Static.AppLauncher = this; + } + + public void Awake() + { + GameEvents.onGUIApplicationLauncherReady.Add(OnGUIApplicationLauncherReady); + GameEvents.onGameSceneLoadRequested.Add(OnSceneChangeRequest); + GameEvents.onShowUI.Add(OnShowUI); + GameEvents.onHideUI.Add(OnHideUI); + } + + internal void OnDestroy() + { + GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIApplicationLauncherReady); + GameEvents.onGameSceneLoadRequested.Remove(OnSceneChangeRequest); + GameEvents.onShowUI.Remove(OnShowUI); + GameEvents.onHideUI.Remove(OnHideUI); + RemoveAppLauncherButton(); + Static.AppLauncher = null; + } + + public void OnGUI() + { + _settingsWindow.DrawGUI(); + } + + void OnGUIApplicationLauncherReady() + { + AddAppLauncherButton(); + } + + void OnSceneChangeRequest(GameScenes scene) + { + RemoveAppLauncherButton(); + } + + void OnShowUI() + { + _settingsWindow.CanShow = true; + } + + void OnHideUI() + { + _settingsWindow.CanShow = false; + } + + /// Shows the settings window when the button is pressed. + void OnButtonOn() + { + _settingsWindow.Show(); + } + + /// Hides the settings window when the button is pressed again. + void OnButtonOff() + { + _settingsWindow.Hide(); + } + + /// Adds the button to the appLauncher. + void AddAppLauncherButton() + { + if(_appLauncherButton == null) + _appLauncherButton = ApplicationLauncher.Instance.AddModApplication( + onTrue: OnButtonOn, + onFalse: OnButtonOff, + onHover: null, + onHoverOut: null, + onEnable: null, + onDisable: null, + visibleInScenes: ApplicationLauncher.AppScenes.NEVER, + texture: AppLauncherButtonTexture); + Update(); + } + + /// Removes the button from the appLauncher. + void RemoveAppLauncherButton() + { + if(_appLauncherButton != null) + ApplicationLauncher.Instance.RemoveModApplication(_appLauncherButton); + } + } +} diff --git a/src/CriticalTemperatureGauge/BlizzysToolbar.cs b/src/CriticalTemperatureGauge/BlizzysToolbar.cs new file mode 100644 index 0000000..5d756e3 --- /dev/null +++ b/src/CriticalTemperatureGauge/BlizzysToolbar.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CriticalTemperatureGauge +{ + public class BlizzysToolbar + { + const string ButtonId = "Settings"; + const string ButtonTexturePath = Static.TexturePath + "BizzysToolbarButton"; + + IButton _toolbarButton; + + public void Start() + { + if(ToolbarManager.ToolbarAvailable) + { + _toolbarButton = ToolbarManager.Instance.add(nameof(CriticalTemperatureGauge), nameof(CriticalTemperatureGauge) + ButtonId); + _toolbarButton.TexturePath = ButtonTexturePath; + _toolbarButton.ToolTip = Static.PluginTitle; + _toolbarButton.OnClick += e => + { + if(Static.AppLauncher != null && e.MouseButton == 0 /* Left mouse button */) + Static.AppLauncher.ButtonState = !Static.AppLauncher.ButtonState; + }; + } + } + + public void Destroy() + { + _toolbarButton?.Destroy(); + } + } +} diff --git a/src/CriticalTemperatureGauge/BlizzysToolbarWrapper.cs b/src/CriticalTemperatureGauge/BlizzysToolbarWrapper.cs new file mode 100644 index 0000000..0e8ac9e --- /dev/null +++ b/src/CriticalTemperatureGauge/BlizzysToolbarWrapper.cs @@ -0,0 +1,893 @@ +/* +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.Linq; +using System.Reflection; +using UnityEngine; + + +// TODO: Change to your plugin's namespace here. +namespace CriticalTemperatureGauge +{ + + + + /**********************************************************\ + * --- 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) + { + 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 +} diff --git a/src/CriticalTemperatureGauge/CriticalTemperatureGauge.csproj b/src/CriticalTemperatureGauge/CriticalTemperatureGauge.csproj index 0a6d26d..579102f 100644 --- a/src/CriticalTemperatureGauge/CriticalTemperatureGauge.csproj +++ b/src/CriticalTemperatureGauge/CriticalTemperatureGauge.csproj @@ -51,14 +51,17 @@ - + + - + + + diff --git a/src/CriticalTemperatureGauge/Flight.cs b/src/CriticalTemperatureGauge/Flight.cs index 0f4ebfb..4d48fd4 100644 --- a/src/CriticalTemperatureGauge/Flight.cs +++ b/src/CriticalTemperatureGauge/Flight.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace CriticalTemperatureGauge @@ -12,22 +11,47 @@ namespace CriticalTemperatureGauge [KSPAddon(KSPAddon.Startup.Flight, false)] public class Flight : MonoBehaviour { - Window _gaugeWindow; + readonly Window _gaugeWindow = new GaugeWindow(); + readonly Highlighter _highlighter = new Highlighter(); + readonly BlizzysToolbar _toolbar = new BlizzysToolbar(); // KSP events: public void Start() { - Debug.Log($"CriticalTemperatureGauge: Entering scene {HighLogic.LoadedScene}."); - _gaugeWindow = new GaugeWindow(); + Debug.Log($"{nameof(CriticalTemperatureGauge)}: Entering scene {HighLogic.LoadedScene}."); + _toolbar.Start(); + } + + public void Awake() + { + GameEvents.onShowUI.Add(OnShowUI); + GameEvents.onHideUI.Add(OnHideUI); } public void OnDestroy() { + GameEvents.onShowUI.Remove(OnShowUI); + GameEvents.onHideUI.Remove(OnHideUI); _gaugeWindow?.Hide(); + if(Static.AppLauncher != null) + Static.AppLauncher.ButtonState = false; Static.CriticalPartState = null; + _toolbar.Destroy(); Static.Settings.Save(); - Debug.Log($"CriticalTemperatureGauge: Exiting scene {HighLogic.LoadedScene}."); + Debug.Log($"{nameof(CriticalTemperatureGauge)}: Exiting scene {HighLogic.LoadedScene}."); + } + + void OnShowUI() + { + if(_gaugeWindow != null) + _gaugeWindow.CanShow = true; + } + + void OnHideUI() + { + if(_gaugeWindow != null) + _gaugeWindow.CanShow = false; } public void OnGUI() @@ -38,7 +62,6 @@ public void OnGUI() public void Update() { var vessel = FlightGlobals.ActiveVessel; - if(_gaugeWindow != null && vessel != null) { // Updating critical part state @@ -47,31 +70,37 @@ public void Update() Static.CriticalPartState = criticalPartState; // Determining if the gauge should be shown or hidden - if(!_gaugeWindow.IsVisible && + if(!_gaugeWindow.IsLogicallyVisible && criticalPartState != null && (criticalPartState.Index > Static.Settings.GaugeShowingThreshold || Static.Settings.ForceShowGauge)) { _gaugeWindow.Show(); - // (Part highlighting does not work for some reason) - //if(Static.Settings.HighlightCriticalPart) - // HighlightPart(vessel, criticalPartState.Id); } - else if(_gaugeWindow.IsVisible && + else if(_gaugeWindow.IsLogicallyVisible && (criticalPartState == null || criticalPartState.Index < Static.Settings.GaugeHidingThreshold && !Static.Settings.ForceShowGauge)) { _gaugeWindow.Hide(); - //HighlightNone(vessel); } + + // Highlighting the critical part if needed + _highlighter.SetHighlightedPart( + Static.Settings.HighlightCriticalPart && + criticalPartState != null && + (_highlighter.IsThereHighlightedPart && + criticalPartState.Index > Static.Settings.GaugeHidingThreshold || + criticalPartState.Index > Static.Settings.GaugeShowingThreshold) + ? criticalPartState.Part + : null); } } /// Finds the part with the greatest Temp/TempLimit ratio. /// Current vessel. /// Critical part state. - PartState GetCriticalPartState(Vessel vessel) => + static PartState GetCriticalPartState(Vessel vessel) => vessel.parts .Where(IsPartNotIgnored) .Select(GetPartState) @@ -85,6 +114,7 @@ public void Update() new PartState { Time = Planetarium.GetUniversalTime(), + Part = part, Id = part.flightID, Name = GetPartTitle(part), CoreTemperatureLimit = part.maxTemp, @@ -96,23 +126,9 @@ public void Update() /// Determines if the part has a module containing in the exclusion list. /// A vessel part. /// false if the part is ignored; true otherwise. - bool IsPartNotIgnored(Part part) => - !(Static.Settings.UseExclusionList && Static.Settings.ExclusionListItems.Any(moduleName => part.Modules.Contains(moduleName))); - - // Currently, not used - static void HighlightNone(Vessel craft) => HighlightPart(craft, 0); - - // Currently, not used - static void HighlightPart(Vessel craft, uint partId) - { - foreach(var part in craft.parts) - { - if(part.flightID == partId) - part.highlighter.FlashingOn(Color.red, Color.yellow, 0.5F); - else - part.highlighter.FlashingOff(); - } - } + static bool IsPartNotIgnored(Part part) => + !(Static.Settings.UseExclusionList && + Static.Settings.ExclusionListItems.Any(moduleName => part.Modules.Contains(moduleName))); /// Gets the title (long name) of a part. /// A vessel part. @@ -126,18 +142,15 @@ static string GetPartTitle(Part part) : part.name; // Trying to get part title; using part name if failed - string title; try { - title = PartLoader.getPartInfoByName(name).title; - if(string.IsNullOrEmpty(title)) - title = name; + var title = PartLoader.getPartInfoByName(name).title; + return string.IsNullOrEmpty(title) ? title : name; } catch { - title = name; + return name; } - return title; } } } diff --git a/src/CriticalTemperatureGauge/GaugeWindow.cs b/src/CriticalTemperatureGauge/GaugeWindow.cs index bdb4bf6..56642cc 100644 --- a/src/CriticalTemperatureGauge/GaugeWindow.cs +++ b/src/CriticalTemperatureGauge/GaugeWindow.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace CriticalTemperatureGauge diff --git a/src/CriticalTemperatureGauge/Highlighter.cs b/src/CriticalTemperatureGauge/Highlighter.cs new file mode 100644 index 0000000..993c3a1 --- /dev/null +++ b/src/CriticalTemperatureGauge/Highlighter.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace CriticalTemperatureGauge +{ + /// + /// Part highlighting. + /// + public class Highlighter + { + // Highlight color sequence + static readonly Color[] HighlightColors = + { + Color.yellow, + Color.red, + Color.blue, + }; + + const int FlashPeriod = 4; + + int _currentHighlightColor = 0; + Part _previousHighlightedPart = null; + + /// Returns whether there is a highlighted part. + public bool IsThereHighlightedPart { get; private set; } + + /// Highlights a given part. + /// Part to higilight or null. + public void SetHighlightedPart(Part part) + { + IsThereHighlightedPart = part != null; + if(part != _previousHighlightedPart) + { + ResetPartHighlight(_previousHighlightedPart); + _previousHighlightedPart = part; + } + SetPartHighlight(part); + } + + void ResetPartHighlight(Part part) + { + if(part != null) + { + part.SetHighlightDefault(); + part.SetHighlight(false, false); + } + } + + void SetPartHighlight(Part part) + { + if(part != null) + { + part.highlightType = Part.HighlightType.AlwaysOn; + part.SetHighlightColor(HighlightColors[_currentHighlightColor / FlashPeriod]); + part.SetHighlight(true, false); + } + _currentHighlightColor = (_currentHighlightColor + 1) % (HighlightColors.Length * FlashPeriod); + } + } +} diff --git a/src/CriticalTemperatureGauge/PartState.cs b/src/CriticalTemperatureGauge/PartState.cs index d1c267c..f481362 100644 --- a/src/CriticalTemperatureGauge/PartState.cs +++ b/src/CriticalTemperatureGauge/PartState.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; namespace CriticalTemperatureGauge { @@ -13,6 +12,9 @@ public class PartState /// Moment of time the parameters were measured at. public double Time { get; set; } + /// Vessel part. + public Part Part { get; set; } + /// Vessel part Id. public uint Id { get; set; } diff --git a/src/CriticalTemperatureGauge/Properties/AssemblyInfo.cs b/src/CriticalTemperatureGauge/Properties/AssemblyInfo.cs index affed35..f354b4f 100644 --- a/src/CriticalTemperatureGauge/Properties/AssemblyInfo.cs +++ b/src/CriticalTemperatureGauge/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("CriticalTemperatureGauge")] +[assembly: AssemblyTitle(nameof(CriticalTemperatureGauge))] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("CriticalTemperatureGauge")] +[assembly: AssemblyProduct(nameof(CriticalTemperatureGauge))] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.3.3")] -[assembly: AssemblyFileVersion("1.1.3.3")] +[assembly: AssemblyVersion("1.1.3.4")] +[assembly: AssemblyFileVersion("1.1.3.4")] diff --git a/src/CriticalTemperatureGauge/Settings.cs b/src/CriticalTemperatureGauge/Settings.cs index 85f4932..78db1d2 100644 --- a/src/CriticalTemperatureGauge/Settings.cs +++ b/src/CriticalTemperatureGauge/Settings.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using KSP.IO; using UnityEngine; @@ -14,8 +13,9 @@ namespace CriticalTemperatureGauge public class Settings { // Window settings - public Vector2 ConfigWindowPosition { get; set; } + public Vector2 SettingsWindowPosition { get; set; } public Vector2 GaugeWindowPosition { get; set; } + public bool ShowAppLauncherButton { get; set; } public bool LockGaugeWindow { get; set; } // Additional information settings @@ -23,9 +23,7 @@ public class Settings public bool ShowTemperatureLimit { get; set; } public bool ShowTemperatureRate { get; set; } public bool ShowCriticalPart { get; set; } - - // (Part highlighting does not work for some reason) - //public bool HighlightCriticalPart { get; set; } + public bool HighlightCriticalPart { get; set; } // Gauge visibility settings @@ -77,47 +75,49 @@ public string ExclusionList /// Saves the settings to an XML file inside PluginData directory. public void Save() { - var config = PluginConfiguration.CreateForType(); - - config.SetValue(nameof(ConfigWindowPosition), ConfigWindowPosition); - config.SetValue(nameof(GaugeWindowPosition), GaugeWindowPosition); - config.SetValue(nameof(LockGaugeWindow), LockGaugeWindow); - config.SetValue(nameof(ForceShowGauge), ForceShowGauge); - config.SetValue(nameof(GaugeShowingThreshold), GaugeShowingThreshold); - config.SetValue(nameof(GaugeHidingThreshold), GaugeHidingThreshold); - config.SetValue(nameof(ShowTemperature), ShowTemperature); - config.SetValue(nameof(ShowTemperatureLimit), ShowTemperatureLimit); - config.SetValue(nameof(ShowTemperatureRate), ShowTemperatureRate); - config.SetValue(nameof(ShowCriticalPart), ShowCriticalPart); - //config.SetValue(nameof(HighlightCriticalPart), HighlightCriticalPart); - config.SetValue(nameof(UseExclusionList), UseExclusionList); - config.SetValue(nameof(ExclusionList), ExclusionList); - - config.save(); + var settings = PluginConfiguration.CreateForType(); + + settings.SetValue(nameof(SettingsWindowPosition), SettingsWindowPosition); + settings.SetValue(nameof(GaugeWindowPosition), GaugeWindowPosition); + settings.SetValue(nameof(ShowAppLauncherButton), ShowAppLauncherButton); + settings.SetValue(nameof(LockGaugeWindow), LockGaugeWindow); + settings.SetValue(nameof(ForceShowGauge), ForceShowGauge); + settings.SetValue(nameof(GaugeShowingThreshold), GaugeShowingThreshold); + settings.SetValue(nameof(GaugeHidingThreshold), GaugeHidingThreshold); + settings.SetValue(nameof(ShowTemperature), ShowTemperature); + settings.SetValue(nameof(ShowTemperatureLimit), ShowTemperatureLimit); + settings.SetValue(nameof(ShowTemperatureRate), ShowTemperatureRate); + settings.SetValue(nameof(ShowCriticalPart), ShowCriticalPart); + settings.SetValue(nameof(HighlightCriticalPart), HighlightCriticalPart); + settings.SetValue(nameof(UseExclusionList), UseExclusionList); + settings.SetValue(nameof(ExclusionList), ExclusionList); + + settings.save(); } /// Loads settings from an XML file inside PluginData directory. /// Loaded settings. public static Settings Load() { - var config = PluginConfiguration.CreateForType(); - config.load(); + var settings = PluginConfiguration.CreateForType(); + settings.load(); return new Settings { - ConfigWindowPosition = config.GetValue(nameof(ConfigWindowPosition), Vector2.zero), - GaugeWindowPosition = config.GetValue(nameof(GaugeWindowPosition), Vector2.zero), - LockGaugeWindow = config.GetValue(nameof(LockGaugeWindow), true), - ForceShowGauge = config.GetValue(nameof(ForceShowGauge), false), - GaugeShowingThreshold = config.GetValue(nameof(GaugeShowingThreshold), DefaultGaugeShowingThreshold), - GaugeHidingThreshold = config.GetValue(nameof(GaugeHidingThreshold), DefaultGaugeHidingThreshold), - ShowTemperature = config.GetValue(nameof(ShowTemperature), true), - ShowTemperatureLimit = config.GetValue(nameof(ShowTemperatureLimit), true), - ShowTemperatureRate = config.GetValue(nameof(ShowTemperatureRate), true), - ShowCriticalPart = config.GetValue(nameof(ShowCriticalPart), true), - //HighlightCriticalPart = config.GetValue(nameof(HighlightCriticalPart), false), - UseExclusionList = config.GetValue(nameof(UseExclusionList), false), - ExclusionList = config.GetValue(nameof(ExclusionList), ""), + SettingsWindowPosition = settings.GetValue(nameof(SettingsWindowPosition), Vector2.zero), + GaugeWindowPosition = settings.GetValue(nameof(GaugeWindowPosition), Vector2.zero), + ShowAppLauncherButton = settings.GetValue(nameof(ShowAppLauncherButton), true), + LockGaugeWindow = settings.GetValue(nameof(LockGaugeWindow), true), + ForceShowGauge = settings.GetValue(nameof(ForceShowGauge), false), + GaugeShowingThreshold = settings.GetValue(nameof(GaugeShowingThreshold), DefaultGaugeShowingThreshold), + GaugeHidingThreshold = settings.GetValue(nameof(GaugeHidingThreshold), DefaultGaugeHidingThreshold), + ShowTemperature = settings.GetValue(nameof(ShowTemperature), true), + ShowTemperatureLimit = settings.GetValue(nameof(ShowTemperatureLimit), true), + ShowTemperatureRate = settings.GetValue(nameof(ShowTemperatureRate), true), + ShowCriticalPart = settings.GetValue(nameof(ShowCriticalPart), true), + HighlightCriticalPart = settings.GetValue(nameof(HighlightCriticalPart), false), + UseExclusionList = settings.GetValue(nameof(UseExclusionList), false), + ExclusionList = settings.GetValue(nameof(ExclusionList), ""), }; } } diff --git a/src/CriticalTemperatureGauge/ConfigWindow.cs b/src/CriticalTemperatureGauge/SettingsWindow.cs similarity index 75% rename from src/CriticalTemperatureGauge/ConfigWindow.cs rename to src/CriticalTemperatureGauge/SettingsWindow.cs index e61ef55..e671257 100644 --- a/src/CriticalTemperatureGauge/ConfigWindow.cs +++ b/src/CriticalTemperatureGauge/SettingsWindow.cs @@ -1,17 +1,16 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace CriticalTemperatureGauge { /// - /// Represents the configuration window. + /// Represents the settings window. /// - public class ConfigWindow : Window + public class SettingsWindow : Window { - /// Slider resolution.. + /// Slider resolution. const int ThresholdSteps = 20; // Layout parameters @@ -20,19 +19,19 @@ public class ConfigWindow : Window protected override Rect InitialWindowRectangle => new Rect( - Static.Settings.ConfigWindowPosition != Vector2.zero - ? Static.Settings.ConfigWindowPosition + Static.Settings.SettingsWindowPosition != Vector2.zero + ? Static.Settings.SettingsWindowPosition : new Vector2(Screen.width - 285, (Screen.height - 410) / 2), Vector2.zero); - /// Creates the configuration window. - public ConfigWindow() - : base(Static.Settings.BaseWindowId + 1, "Critical Temperature Gauge") { } + /// Creates the settings window. + public SettingsWindow() + : base(Static.Settings.BaseWindowId + 1, Static.PluginTitle + " ") { } /// Writes current window position into settings. protected override void OnWindowRectUpdated() { - Static.Settings.ConfigWindowPosition = WindowRectangle.position; + Static.Settings.SettingsWindowPosition = WindowRectangle.position; } /// Draws the window contents. @@ -40,7 +39,11 @@ protected override void OnWindowRectUpdated() protected override void WindowGUI(int windowId) { // Defining styles - var windowStyle = new GUIStyle(GUI.skin.window) { padding = new RectOffset(8, 8, 8, 8) }; + var closeButtonStyle = new GUIStyle(GUI.skin.button) + { + alignment = TextAnchor.MiddleCenter, + padding = new RectOffset(0, 0, 3, 0), + }; var textEditStyle = new GUIStyle(GUI.skin.textField); var labelStyle = new GUIStyle(GUI.skin.label) { @@ -51,6 +54,9 @@ protected override void WindowGUI(int windowId) var sliderStyle = new GUIStyle(GUI.skin.horizontalSlider) { fixedWidth = 222 }; var sliderThumbStyle = new GUIStyle(GUI.skin.horizontalSliderThumb); + if(GUI.Button(new Rect(WindowRectangle.width - 19, 3, 17, 17), "×", closeButtonStyle)) + Static.AppLauncher.ButtonState = false; + // Drawing layout GUILayout.Space(SeparatorHeight); @@ -70,9 +76,8 @@ protected override void WindowGUI(int windowId) Static.Settings.ShowTemperatureLimit = GUILayout.Toggle(Static.Settings.ShowTemperatureLimit, "Show temperature limit"); GUILayout.EndHorizontal(); Static.Settings.ShowTemperatureRate = GUILayout.Toggle(Static.Settings.ShowTemperatureRate, "Show temperature rate"); - Static.Settings.ShowCriticalPart = GUILayout.Toggle(Static.Settings.ShowCriticalPart, "Show critical part"); - // (Part highlighting does not work for some reason) - //Static.Settings.HighlightCriticalPart = GUILayout.Toggle(Static.Settings.HighlightCriticalPart, "Highlight critical part"); + Static.Settings.ShowCriticalPart = GUILayout.Toggle(Static.Settings.ShowCriticalPart, "Show critical part name"); + Static.Settings.HighlightCriticalPart = GUILayout.Toggle(Static.Settings.HighlightCriticalPart, "Highlight critical part"); // Drawing exclusion list settings controls GUILayout.Space(SeparatorHeight); @@ -83,6 +88,8 @@ protected override void WindowGUI(int windowId) // Drawing interface settings controls GUILayout.Space(SeparatorHeight); Static.Settings.LockGaugeWindow = GUILayout.Toggle(Static.Settings.LockGaugeWindow, "Lock gauge position"); + Static.Settings.ShowAppLauncherButton = GUILayout.Toggle(Static.Settings.ShowAppLauncherButton, "Show AppLauncher button"); + Static.AppLauncher.Update(); GUI.DragWindow(); } diff --git a/src/CriticalTemperatureGauge/Static.cs b/src/CriticalTemperatureGauge/Static.cs index 425f770..b63a5da 100644 --- a/src/CriticalTemperatureGauge/Static.cs +++ b/src/CriticalTemperatureGauge/Static.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; -using System.Text; namespace CriticalTemperatureGauge { @@ -11,12 +9,18 @@ namespace CriticalTemperatureGauge /// public static class Static { + /// User-friendly name of the plugin. + public const string PluginTitle = "Critical Temperature Gauge"; + /// Path to the Textures folder inside the add-on folder. public const string TexturePath = nameof(CriticalTemperatureGauge) + "/Textures/"; - static Settings _settings; /// Add-on settings. public static Settings Settings => _settings ?? (_settings = Settings.Load()); + static Settings _settings; + + /// AppLauncher button. + public static AppLauncher AppLauncher { get; set; } /// Current critical part state. /// null if there is no current critical part. diff --git a/src/CriticalTemperatureGauge/Toolbar.cs b/src/CriticalTemperatureGauge/Toolbar.cs deleted file mode 100644 index d334f44..0000000 --- a/src/CriticalTemperatureGauge/Toolbar.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using KSP.UI.Screens; -using UnityEngine; - -namespace CriticalTemperatureGauge -{ - /// - /// Class that adds the toolbar button. - /// - [KSPAddon(KSPAddon.Startup.Flight, false)] - public class Toolbar : MonoBehaviour - { - // Resources - static readonly Texture2D ToolbarButtonTexture = GameDatabase.Instance.GetTexture(Static.TexturePath + "ToolbarButton", false); - - readonly ConfigWindow _configWindow = new ConfigWindow(); - ApplicationLauncherButton _toolbarButton; - - // KSP events: - - public void Start() - { - OnGUIApplicationLauncherReady(); - } - - public void Awake() - { - GameEvents.onGUIApplicationLauncherReady.Add(OnGUIApplicationLauncherReady); - GameEvents.onGameSceneLoadRequested.Add(OnSceneChangeRequest); - } - - internal void OnDestroy() - { - GameEvents.onGUIApplicationLauncherReady.Remove(OnGUIApplicationLauncherReady); - GameEvents.onGameSceneLoadRequested.Remove(OnSceneChangeRequest); - RemoveToolbarButton(); - } - - public void OnGUI() - { - _configWindow?.DrawGUI(); - } - - void OnGUIApplicationLauncherReady() - { - AddToolbarButton(); - } - - void OnSceneChangeRequest(GameScenes scene) - { - RemoveToolbarButton(); - } - - /// Shows the configuration window when the button is pressed. - void OnButtonOn() - { - _configWindow?.Show(); - } - - /// Hides the configuration window when the button is pressed again. - void OnButtonOff() - { - _configWindow?.Hide(); - } - - /// Adds the button to the toolbar. - void AddToolbarButton() - { - if(_toolbarButton == null) - _toolbarButton = ApplicationLauncher.Instance.AddModApplication( - onTrue: OnButtonOn, - onFalse: OnButtonOff, - onHover: null, - onHoverOut: null, - onEnable: null, - onDisable: null, - visibleInScenes: ApplicationLauncher.AppScenes.FLIGHT | ApplicationLauncher.AppScenes.MAPVIEW, - texture: ToolbarButtonTexture); - } - - /// Removes the button from the toolbar. - void RemoveToolbarButton() - { - if(_toolbarButton != null) - ApplicationLauncher.Instance.RemoveModApplication(_toolbarButton); - } - } -} diff --git a/src/CriticalTemperatureGauge/Window.cs b/src/CriticalTemperatureGauge/Window.cs index be033e8..f94f4fb 100644 --- a/src/CriticalTemperatureGauge/Window.cs +++ b/src/CriticalTemperatureGauge/Window.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using UnityEngine; namespace CriticalTemperatureGauge @@ -12,9 +11,20 @@ namespace CriticalTemperatureGauge public abstract class Window { public int WindowId { get; } + public string Title { get; } + + /// Is the background of the window transparent. public bool HasClearBackground { get; } - public bool IsVisible { get; private set; } + + /// Should the window be visible? (Disregarding the F2 key.) + public bool IsLogicallyVisible { get; private set; } + + /// false, if the F2 key pressed, true otherwise. + public bool CanShow { get; set; } = true; + + /// Is the window visible? + public bool IsVisible => CanShow && IsLogicallyVisible; Rect? _windowRectangle; public Rect WindowRectangle @@ -39,12 +49,17 @@ protected Window(int windowId, string title = "", bool hasClearBackground = fals public void Show() { - IsVisible = true; + IsLogicallyVisible = true; } public void Hide() { - IsVisible = false; + IsLogicallyVisible = false; + } + + public void Toggle() + { + IsLogicallyVisible = !IsLogicallyVisible; } public void DrawGUI() diff --git a/src/Graphics/ToolbarIcon.svg b/src/Graphics/ToolbarIcon.svg new file mode 100644 index 0000000..7a59b54 --- /dev/null +++ b/src/Graphics/ToolbarIcon.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + +