diff --git a/LICENSE b/LICENSE index 2eafab0..e620321 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Micrologist +Copyright (c) 2023 Micrologist, Falki-git Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs index 9e1f3d8..2ebc799 100644 --- a/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs +++ b/MicroEngineerProject/MicroEngineer/Entries/BaseEntry.cs @@ -11,6 +11,7 @@ public class BaseEntry [JsonProperty] public string Name; [JsonProperty] + public Guid Id; public string Description; [JsonProperty] public MicroEntryCategory Category; diff --git a/MicroEngineerProject/MicroEngineer/Managers/Manager.cs b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs index e2a6172..d74d035 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/Manager.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/Manager.cs @@ -7,22 +7,30 @@ namespace MicroMod { internal class Manager { + private static Manager _instance; + internal List Windows; internal List Entries; - internal UI UI; - internal MessageManager MessageManager; - private MicroEngineerMod _plugin; private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Manager"); - internal Manager(MicroEngineerMod plugin) + public List TextFieldNames = new List(); + + internal Manager() { - _plugin = plugin; Entries = InitializeEntries(); Windows = InitializeWindows(); + } - // Load window positions and states from disk, if file exists - Utility.LoadLayout(Windows); + public static Manager Instance + { + get + { + if (_instance == null) + _instance = new Manager(); + + return _instance; + } } public void Update() @@ -297,17 +305,28 @@ internal void ResetLayout() Entries.Clear(); Entries = InitializeEntries(); Windows = InitializeWindows(); - UI.Windows = Windows; - MessageManager.Windows = Windows; } internal void LoadLayout() { Utility.LoadLayout(Windows); - UI.Windows = Windows; - MessageManager.Windows = Windows; } internal void SaveLayout() => Utility.SaveLayout(Windows); + + public void PupulateTextFieldNames(List entries) + { + TextFieldNames.Clear(); + TextFieldNames.Add(Utility.InputDisableWindowAbbreviation); + TextFieldNames.Add(Utility.InputDisableWindowName); + + foreach (var entry in entries) + { + entry.Id = Guid.NewGuid(); + TextFieldNames.Add(entry.Id.ToString()); + } + } + + public void AddTextFieldName(string name) => TextFieldNames.Add(name); } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs index 6d41071..990f1e0 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/MessageManager.cs @@ -7,25 +7,26 @@ namespace MicroMod { internal class MessageManager { - MicroEngineerMod _plugin; - private Manager _manager; - private UI _ui; - internal List Windows; + private static MessageManager _instance; - internal MessageManager(MicroEngineerMod plugin, Manager manager, UI ui) + internal MessageManager() + { } + + public static MessageManager Instance { - _plugin = plugin; - _manager = manager; - _ui = ui; - Windows = _manager.Windows; + get + { + if (_instance == null) + _instance = new MessageManager(); - SubscribeToMessages(); + return _instance; + } } /// /// Subscribe to KSP2 messages /// - internal void SubscribeToMessages() + public void SubscribeToMessages() { Utility.RefreshGameManager(); @@ -50,21 +51,21 @@ internal void SubscribeToMessages() private void OnManeuverCreatedMessage(MessageCenterMessage message) { - var maneuverWindow = Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; + var maneuverWindow = Manager.Instance.Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; maneuverWindow.OnManeuverCreatedMessage(message); } private void OnManeuverRemovedMessage(MessageCenterMessage message) { - var maneuverWindow = Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; + var maneuverWindow = Manager.Instance.Windows.Find(w => w.GetType() == typeof(ManeuverWindow)) as ManeuverWindow; maneuverWindow.OnManeuverRemovedMessage(message); } private void OnPartManipulationCompletedMessage(MessageCenterMessage obj) { - EntryWindow stageInfoOabWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); - Torque torque = (Torque)Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Torque"); + Torque torque = (Torque)Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Torque"); torque.RefreshData(); } @@ -73,22 +74,20 @@ private void GameStateEntered(MessageCenterMessage obj) Utility.RefreshGameManager(); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) { - Utility.LoadLayout(Windows); - _manager.Windows = Windows; - _ui.Windows = Windows; + Utility.LoadLayout(Manager.Instance.Windows); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) { - _ui.ShowGuiFlight = Windows.OfType().FirstOrDefault().IsFlightActive; - GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(_ui.ShowGuiFlight); + UI.Instance.ShowGuiFlight = Manager.Instance.Windows.OfType().FirstOrDefault().IsFlightActive; + GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(UI.Instance.ShowGuiFlight); } if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) { - _ui.ShowGuiOAB = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive; - GameObject.Find("BTN - MicroEngineerOAB")?.GetComponent()?.SetValue(_ui.ShowGuiOAB); - _ui.CelestialBodies.GetBodies(); - _ui.CelestialBodySelectionStageIndex = -1; + UI.Instance.ShowGuiOAB = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive; + GameObject.Find("BTN - MicroEngineerOAB")?.GetComponent()?.SetValue(UI.Instance.ShowGuiOAB); + UI.Instance.CelestialBodies.GetBodies(); + UI.Instance.CelestialBodySelectionStageIndex = -1; Styles.SetActiveTheme(Theme.Gray); // TODO implement other themes in OAB } } @@ -99,13 +98,13 @@ private void GameStateLeft(MessageCenterMessage obj) Utility.RefreshGameManager(); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.VehicleAssemblyBuilder || Utility.GameState.GameState == GameState.Map3DView) { - Utility.SaveLayout(Windows); + Utility.SaveLayout(Manager.Instance.Windows); if (Utility.GameState.GameState == GameState.FlightView || Utility.GameState.GameState == GameState.Map3DView) - _ui.ShowGuiFlight = false; + UI.Instance.ShowGuiFlight = false; if (Utility.GameState.GameState == GameState.VehicleAssemblyBuilder) - _ui.ShowGuiOAB = false; + UI.Instance.ShowGuiOAB = false; } } @@ -123,7 +122,7 @@ private void RefreshStagingDataOAB(MessageCenterMessage obj) Utility.RefreshStagesOAB(); - EntryWindow stageWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + EntryWindow stageWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); if (Utility.VesselDeltaVComponentOAB?.StageInfo == null) { diff --git a/MicroEngineerProject/MicroEngineer/Managers/UI.cs b/MicroEngineerProject/MicroEngineer/Managers/UI.cs index b35bb75..f5dc88c 100644 --- a/MicroEngineerProject/MicroEngineer/Managers/UI.cs +++ b/MicroEngineerProject/MicroEngineer/Managers/UI.cs @@ -8,13 +8,9 @@ namespace MicroMod { internal class UI { - private MicroEngineerMod _plugin; - private Manager _manager; - + private static UI _instance; private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.UI"); - internal List Windows; - internal bool ShowGuiFlight; internal bool ShowGuiOAB; private bool _showGuiSettingsFlight; @@ -40,11 +36,19 @@ internal class UI /// internal MicroCelestialBodies CelestialBodies = new(); - internal UI(MicroEngineerMod plugin, Manager manager) + internal UI() + { + } + + public static UI Instance { - _plugin = plugin; - _manager = manager; - Windows = manager.Windows; + get + { + if (_instance == null) + _instance = new UI(); + + return _instance; + } } internal void OnGUI() @@ -64,7 +68,7 @@ private void OnGUI_Flight() if (!ShowGuiFlight || Utility.ActiveVessel == null) return; - MainGuiWindow mainGui = (MainGuiWindow)Windows.Find(w => w is MainGuiWindow); + MainGuiWindow mainGui = (MainGuiWindow)Manager.Instance.Windows.Find(w => w is MainGuiWindow); // Draw main GUI that contains docked windows mainGui.FlightRect = GUILayout.Window( @@ -77,7 +81,7 @@ private void OnGUI_Flight() ); mainGui.FlightRect.position = Utility.ClampToScreen(mainGui.FlightRect.position, mainGui.FlightRect.size); - List entryWindows = Windows.FindAll(w => w is EntryWindow).Cast().ToList(); + List entryWindows = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList(); // Draw all other popped out windows foreach (var (window, index) in entryWindows @@ -110,6 +114,11 @@ private void OnGUI_Flight() if (window.IsLocked) GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1); + // Snap popped out windows + var settings = Manager.Instance.Windows.Find(w => w is SettingsWIndow) as SettingsWIndow; + if (settings.SnapWindows && window.IsBeingDragged) + HandleSnapping(window); + window.FlightRect.position = Utility.ClampToScreen(window.FlightRect.position, window.FlightRect.size); } @@ -156,21 +165,23 @@ private void DrawSettingsFlightWindow(int id) GUILayout.Space(10); GUILayout.Label("Edit window entries"); if (GUILayout.Button("EDIT WINDOWS", Styles.NormalBtnStyle)) + { _showEditWindow = !_showEditWindow; + Manager.Instance.PupulateTextFieldNames(GetEditableWindows()[_selectedWindowId].Entries); + } GUILayout.Space(10); GUILayout.Label("Layout control"); if (GUILayout.Button("SAVE LAYOUT", Styles.NormalBtnStyle)) { - _manager.SaveLayout(); + Manager.Instance.SaveLayout(); _showGuiSettingsFlight = false; - } - GUILayout.Space(5); + } if (GUILayout.Button("LOAD LAYOUT", Styles.NormalBtnStyle)) - _manager.LoadLayout(); + Manager.Instance.LoadLayout(); if (GUILayout.Button("RESET LAYOUT", Styles.NormalBtnStyle)) { - _manager.ResetLayout(); + Manager.Instance.ResetLayout(); _selectedWindowId = 0; } @@ -179,7 +190,7 @@ private void DrawSettingsFlightWindow(int id) GUILayout.Space(-10); GUILayout.BeginHorizontal(); - var settingsWindow = Windows.Find(w => w.GetType() == typeof(SettingsWIndow)) as SettingsWIndow; + var settingsWindow = Manager.Instance.Windows.Find(w => w.GetType() == typeof(SettingsWIndow)) as SettingsWIndow; if (GUILayout.Toggle(Styles.ActiveTheme == Theme.munix, "munix", Styles.SectionToggleStyle)) { Styles.SetActiveTheme(Theme.munix); @@ -199,6 +210,11 @@ private void DrawSettingsFlightWindow(int id) } GUILayout.EndHorizontal(); + GUILayout.Space(10); + GUILayout.Label("Other"); + GUILayout.Space(-10); + settingsWindow.SnapWindows = GUILayout.Toggle(settingsWindow.SnapWindows, "Window snapping", Styles.SectionToggleStyle); + GUI.DragWindow(new Rect(0, 0, Screen.width, Screen.height)); } @@ -206,7 +222,7 @@ private void OnGUI_OAB() { if (!ShowGuiOAB) return; - EntryWindow stageInfoOAB = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + EntryWindow stageInfoOAB = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); if (stageInfoOAB.Entries.Find(e => e.Name == "Stage Info (OAB)").EntryValue == null) return; stageInfoOAB.EditorRect = GUILayout.Window( @@ -261,13 +277,13 @@ private void OnGUI_OAB() /// private void FillMainGUI(int windowID) { - List entryWindows = Windows.FindAll(w => w is EntryWindow).Cast().ToList(); + List entryWindows = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList(); GUILayout.Space(-15); GUILayout.BeginHorizontal(); if (GUILayout.Button(Styles.Settings20Texture, Styles.SettingsMainGuiBtnStyle)) { - Rect mainGuiRect = Windows.OfType().FirstOrDefault().FlightRect; + Rect mainGuiRect = Manager.Instance.Windows.OfType().FirstOrDefault().FlightRect; settingsFlightRect = new Rect(mainGuiRect.x - Styles.WindowWidthSettingsFlight, mainGuiRect.y, Styles.WindowWidthSettingsFlight, 0); _showGuiSettingsFlight = !_showGuiSettingsFlight; } @@ -373,11 +389,12 @@ private void DrawSectionHeader(string sectionName, ref bool isPopout, bool isLoc GUILayout.FlexibleSpace(); if(GUILayout.Button(Styles.Settings15Texture, Styles.SettingsBtnStyle)) { - _selectedWindowId = Windows. + _selectedWindowId = Manager.Instance.Windows. FindAll(w => w is EntryWindow).Cast().ToList(). FindAll(w => w.IsEditable). FindIndex(w => w.Name == sectionName); _showEditWindow = true; + Manager.Instance.PupulateTextFieldNames(GetEditableWindows()[_selectedWindowId].Entries); } isPopout = isPopout && !isLocked ? !CloseButton(Styles.CloseBtnStyle) : !isPopout ? GUILayout.Button(Styles.PopoutTexture, Styles.PopoutBtnStyle) : isPopout; GUILayout.EndHorizontal(); @@ -418,8 +435,8 @@ private void DrawSectionEnd(EntryWindow window) /// private void DrawEditWindow(int windowIndex) { - List editableWindows = Windows.FindAll(w => w is EntryWindow).Cast().ToList().FindAll(w => w.IsEditable); // Editable windows are all except MainGUI, Settings, Stage and StageInfoOAB - List entriesByCategory = _manager.Entries.FindAll(e => e.Category == _selectedCategory); // All window stageInfoOabEntries belong to a category, but they can still be placed in any window + List editableWindows = GetEditableWindows(); + List entriesByCategory = Manager.Instance.Entries.FindAll(e => e.Category == _selectedCategory); // All entries belong to a category, but they can still be placed in any window GUILayout.Space(-5); GUILayout.BeginHorizontal(); @@ -435,6 +452,7 @@ private void DrawEditWindow(int windowIndex) if (GUILayout.Button("<", Styles.OneCharacterHighBtnStyle)) { _selectedWindowId = _selectedWindowId > 0 ? _selectedWindowId - 1 : editableWindows.Count - 1; + Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); } GUI.SetNextControlName(Utility.InputDisableWindowAbbreviation); editableWindows[_selectedWindowId].Abbreviation = GUILayout.TextField(editableWindows[_selectedWindowId].Abbreviation, Styles.WindowSelectionAbbrevitionTextFieldStyle); @@ -444,6 +462,7 @@ private void DrawEditWindow(int windowIndex) if (GUILayout.Button(">", Styles.OneCharacterHighBtnStyle)) { _selectedWindowId = _selectedWindowId < editableWindows.Count - 1 ? _selectedWindowId + 1 : 0; + Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); } GUILayout.EndHorizontal(); #endregion @@ -459,13 +478,13 @@ private void DrawEditWindow(int windowIndex) { if (GUILayout.Button("DEL WINDOW", Styles.NormalBtnStyle)) { - Windows.Remove(editableWindows[_selectedWindowId]); + Manager.Instance.Windows.Remove(editableWindows[_selectedWindowId]); editableWindows.Remove(editableWindows[_selectedWindowId]); _selectedWindowId--; } } if (GUILayout.Button("NEW WINDOW", Styles.NormalBtnStyle)) - _selectedWindowId = _manager.CreateCustomWindow(editableWindows); + _selectedWindowId = Manager.Instance.CreateCustomWindow(editableWindows); GUILayout.EndHorizontal(); GUILayout.Space(10); @@ -483,8 +502,10 @@ private void DrawEditWindow(int windowIndex) GUIStyle backgroundStyle = i == 0 ? Styles.EntryBackground_First : i < entries.Count - 1 ? Styles.EntryBackground_Middle : Styles.EntryBackground_Last; GUILayout.BeginHorizontal(backgroundStyle); - - GUILayout.Label(entries[i].Name, Styles.NameLabelStyle); + + GUI.SetNextControlName(entries[i].Id.ToString()); + entries[i].Name = GUILayout.TextField(entries[i].Name, Styles.InstalledEntryFieldStyle); + GUILayout.FlexibleSpace(); GUI.enabled = entries[i].NumberOfDecimalDigits < 5; if (entries[i].Formatting != null && GUILayout.Button(Styles.IncreaseDecimalDigitsTexture, Styles.OneCharacterBtnStyle)) { @@ -560,8 +581,9 @@ private void DrawEditWindow(int windowIndex) } } if (GUILayout.Button("+", Styles.OneCharacterBtnStyle)) - { - editableWindows[_selectedWindowId].AddEntry(entriesByCategory[i]); + { + editableWindows[_selectedWindowId].AddEntry(Activator.CreateInstance(entriesByCategory[i].GetType()) as BaseEntry); + Manager.Instance.PupulateTextFieldNames(editableWindows[_selectedWindowId].Entries); } GUILayout.EndHorizontal(); @@ -579,13 +601,18 @@ private void DrawEditWindow(int windowIndex) GUI.DragWindow(new Rect(0, 0, Styles.WindowWidth, Styles.WindowHeight)); } + private List GetEditableWindows() + { + return Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().FindAll(w => w.IsEditable); // Editable windows are all except MainGUI, Settings, Stage and StageInfoOAB + } + #endregion #region OAB scene UI private void DrawStageInfoOAB(int windowID) { - EntryWindow stageInfoOabWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); List stageInfoOabEntries = stageInfoOabWindow.Entries; GUILayout.BeginHorizontal(); @@ -701,7 +728,7 @@ private void DrawCelestialBodySelection(int id) { if (GUILayout.Button(body.DisplayName, Styles.CelestialSelectionBtnStyle)) { - StageInfo_OAB stageInfoOab = (StageInfo_OAB)Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Stage Info (OAB)"); + StageInfo_OAB stageInfoOab = (StageInfo_OAB)Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).Entries.Find(e => e.Name == "Stage Info (OAB)"); stageInfoOab.CelestialBodyForStage[CelestialBodySelectionStageIndex] = body.Name; // Hide the selection window @@ -722,7 +749,7 @@ private void DrawSettingsOabWindow(int id) _showGuiSettingsOAB = !CloseButton(Styles.CloseBtnStyle); GUILayout.EndHorizontal(); - EntryWindow stageInfoOabWindow = Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); + EntryWindow stageInfoOabWindow = Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB); List stageInfoOabEntries = stageInfoOabWindow.Entries; Torque torqueEntry = (Torque)stageInfoOabEntries.Find(e => e.Name == "Torque"); @@ -748,5 +775,55 @@ internal bool CloseButton(GUIStyle style)//Rect rect) //return GUI.Button(rect, Styles.CloseButtonTexture, Styles.CloseBtnStyle); return GUILayout.Button(Styles.CloseButtonTexture, style); } + + internal void HandleSnapping(EntryWindow draggedWindow) + { + List poppedOutWindows = Manager.Instance.Windows + .FindAll(w => typeof(EntryWindow).IsAssignableFrom(w.GetType())) + .Cast() + .Where(w => w.IsFlightActive && w.IsFlightPoppedOut) + .ToList(); + + var settings = Manager.Instance.Windows.Find(w => w is SettingsWIndow) as SettingsWIndow; + + foreach (var otherWindow in poppedOutWindows) + { + // Check if the current window is close to any edge of the other window + if (otherWindow != draggedWindow && Utility.AreRectsNear(draggedWindow.FlightRect, otherWindow.FlightRect)) + { + // Snap to the left edge + if (Mathf.Abs(draggedWindow.FlightRect.xMin - otherWindow.FlightRect.xMin) < settings.SnapDistance) + draggedWindow.FlightRect.x = otherWindow.FlightRect.xMin; + + // Snap to the right edge + if (Mathf.Abs(draggedWindow.FlightRect.xMax - otherWindow.FlightRect.xMin) < settings.SnapDistance) + draggedWindow.FlightRect.x = otherWindow.FlightRect.xMin - draggedWindow.FlightRect.width; + + // Snap to the left edge + if (Mathf.Abs(draggedWindow.FlightRect.xMin - otherWindow.FlightRect.xMax) < settings.SnapDistance) + draggedWindow.FlightRect.x = otherWindow.FlightRect.xMax; + + // Snap to the right edge + if (Mathf.Abs(draggedWindow.FlightRect.xMax - otherWindow.FlightRect.xMax) < settings.SnapDistance) + draggedWindow.FlightRect.x = otherWindow.FlightRect.xMax - draggedWindow.FlightRect.width; + + // Snap to the top edge + if (Mathf.Abs(draggedWindow.FlightRect.yMin - otherWindow.FlightRect.yMin) < settings.SnapDistance) + draggedWindow.FlightRect.y = otherWindow.FlightRect.yMin; + + // Snap to the bottom edge + if (Mathf.Abs(draggedWindow.FlightRect.yMax - otherWindow.FlightRect.yMin) < settings.SnapDistance) + draggedWindow.FlightRect.y = otherWindow.FlightRect.yMin - draggedWindow.FlightRect.height; + + // Snap to the top edge + if (Mathf.Abs(draggedWindow.FlightRect.yMin - otherWindow.FlightRect.yMax) < settings.SnapDistance) + draggedWindow.FlightRect.y = otherWindow.FlightRect.yMax; + + // Snap to the bottom edge + if (Mathf.Abs(draggedWindow.FlightRect.yMax - otherWindow.FlightRect.yMax) < settings.SnapDistance) + draggedWindow.FlightRect.y = otherWindow.FlightRect.yMax - draggedWindow.FlightRect.height; + } + } + } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs index 3ef3a29..92c080f 100644 --- a/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs +++ b/MicroEngineerProject/MicroEngineer/MicroEngineerMod.cs @@ -8,70 +8,70 @@ namespace MicroMod { - [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "1.0.3")] - [BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)] - public class MicroEngineerMod : BaseSpaceWarpPlugin + //[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] + [BepInPlugin("com.micrologist.microengineer", "MicroEngineer", "1.1.0")] + [BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)] + public class MicroEngineerMod : BaseSpaceWarpPlugin { - private Manager _manager; - private MessageManager _messagesManager; - private UI _ui; + public static MicroEngineerMod Instance { get; set; } + public string GUID; public override void OnInitialized() { - Styles.Initialize(this); + Instance = this; + + GUID = Info.Metadata.GUID; + + BackwardCompatibilityInitializations(); - _manager = new Manager(this); - _ui = new UI(this, _manager); - _messagesManager = new MessageManager(this, _manager, _ui); - _manager.UI = _ui; - _manager.MessageManager = _messagesManager; + Styles.Initialize(); - BackwardCompatibilityInitializations(); + MessageManager.Instance.SubscribeToMessages(); // Register Flight and OAB buttons Appbar.RegisterAppButton( "Micro Engineer", "BTN-MicroEngineerBtn", - AssetManager.GetAsset($"{SpaceWarpMetadata.ModID}/images/icon.png"), + AssetManager.GetAsset($"{GUID}/images/icon.png"), isOpen => { - _ui.ShowGuiFlight = isOpen; - _manager.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = isOpen; + UI.Instance.ShowGuiFlight = isOpen; + Manager.Instance.Windows.Find(w => w.GetType() == typeof(MainGuiWindow)).IsFlightActive = isOpen; GameObject.Find("BTN-MicroEngineerBtn")?.GetComponent()?.SetValue(isOpen); }); Appbar.RegisterOABAppButton( "Micro Engineer", "BTN-MicroEngineerOAB", - AssetManager.GetAsset($"{SpaceWarpMetadata.ModID}/images/icon.png"), + AssetManager.GetAsset($"{GUID}/images/icon.png"), isOpen => { - _ui.ShowGuiOAB = isOpen; - _manager.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive = isOpen; - GameObject.Find("BTN - MicroEngineerOAB")?.GetComponent()?.SetValue(isOpen); + UI.Instance.ShowGuiOAB = isOpen; + Manager.Instance.Windows.FindAll(w => w is EntryWindow).Cast().ToList().Find(w => w.MainWindow == MainWindow.StageInfoOAB).IsEditorActive = isOpen; + GameObject.Find("BTN-MicroEngineerOAB")?.GetComponent()?.SetValue(isOpen); }); } private void BackwardCompatibilityInitializations() { - // Preserve backward compatibility with SpaceWarp 1.0.1 - if (Utility.IsModOlderThan("SpaceWarp", 1, 1, 0)) + // Preserve backward compatibility with SpaceWarp 1.1.x + if (Utility.IsModOlderThan("SpaceWarp", 1, 2, 0)) { - Logger.LogInfo("Space Warp older version detected. Loading old Styles."); - Styles.SetStylesForOldSpaceWarpSkin(); + Logger.LogInfo("Older Space Warp version detected. Setting mod GUID to \"micro_engineer\"."); + GUID = "micro_engineer"; } else - Logger.LogInfo("Space Warp new version detected. Loading new Styles."); + Logger.LogInfo("New Space Warp version detected. No backward compatibility needed."); } - + public void Update() { - _manager?.Update(); + Manager.Instance.Update(); } private void OnGUI() { - _ui?.OnGUI(); + UI.Instance.OnGUI(); } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs b/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs index 50e8bb5..798054b 100644 --- a/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs +++ b/MicroEngineerProject/MicroEngineer/Utilities/Styles.cs @@ -10,8 +10,6 @@ namespace MicroMod public static class Styles { - private static MicroEngineerMod _plugin; - private static readonly ManualLogSource _logger = BepInEx.Logging.Logger.CreateLogSource("MicroEngineer.Styles"); public static int WindowWidth = 290; @@ -44,6 +42,7 @@ public static class Styles public static GUIStyle WindowSelectionTextFieldStyle; public static GUIStyle WindowSelectionAbbrevitionTextFieldStyle; + public static GUIStyle InstalledEntryFieldStyle; public static GUIStyle CloseMainGuiBtnStyle; public static GUIStyle CloseBtnStyle; @@ -124,10 +123,8 @@ public static class Styles public static Theme ActiveTheme; - public static void Initialize(MicroEngineerMod plugin) + public static void Initialize() { - _plugin = plugin; - InitializeTextures(); InitializeStyles(); SetActiveTheme(Theme.Gray); @@ -245,6 +242,8 @@ private static void InitializeStyles() }; BlueLabelStyle.normal.textColor = _valueColor; + ///// TEXTFIELDS ///// + WindowSelectionTextFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) { alignment = TextAnchor.MiddleCenter, @@ -257,6 +256,12 @@ private static void InitializeStyles() fixedWidth = 40 }; + InstalledEntryFieldStyle = new GUIStyle(SpaceWarpUISkin.textField) + { + alignment = TextAnchor.MiddleLeft, + fixedWidth = 120 + }; + ///// BUTTONS ///// CloseMainGuiBtnStyle = new GUIStyle(SpaceWarpUISkin.button) @@ -362,25 +367,25 @@ private static void InitializeTextures() { // Icons from https://icons8.com - Settings20Texture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/settings-20.png"); - Settings15Texture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/settings-15.png"); - CloseButtonTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/close-15.png"); - PopoutTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/popout-15.png"); + Settings20Texture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/settings-20.png"); + Settings15Texture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/settings-15.png"); + CloseButtonTexture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/close-15.png"); + PopoutTexture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/popout-15.png"); - EntryBackgroundTexture_WhiteTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_first.png"); - EntryBackgroundTexture_WhiteTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_middle.png"); - EntryBackgroundTexture_WhiteTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_white_last.png"); + EntryBackgroundTexture_WhiteTheme_First = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_white_first.png"); + EntryBackgroundTexture_WhiteTheme_Middle = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_white_middle.png"); + EntryBackgroundTexture_WhiteTheme_Last = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_white_last.png"); - EntryBackgroundTexture_GrayTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_first.png"); - EntryBackgroundTexture_GrayTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_middle.png"); - EntryBackgroundTexture_GrayTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_darkgray_last.png"); + EntryBackgroundTexture_GrayTheme_First = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_darkgray_first.png"); + EntryBackgroundTexture_GrayTheme_Middle = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_darkgray_middle.png"); + EntryBackgroundTexture_GrayTheme_Last = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_darkgray_last.png"); - EntryBackgroundTexture_BlackTheme_First = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_first.png"); - EntryBackgroundTexture_BlackTheme_Middle = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_middle.png"); - EntryBackgroundTexture_BlackTheme_Last = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/background_black_last.png"); + EntryBackgroundTexture_BlackTheme_First = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_black_first.png"); + EntryBackgroundTexture_BlackTheme_Middle = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_black_middle.png"); + EntryBackgroundTexture_BlackTheme_Last = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/background_black_last.png"); - IncreaseDecimalDigitsTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/increase-decimal-19.png"); - DecreaseDecimalDigitsTexture = LoadTexture($"{_plugin.SpaceWarpMetadata.ModID}/images/decrease-decimal-19.png"); + IncreaseDecimalDigitsTexture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/increase-decimal-19.png"); + DecreaseDecimalDigitsTexture = LoadTexture($"{MicroEngineerMod.Instance.GUID}/images/decrease-decimal-19.png"); } private static Texture2D LoadTexture(string path) diff --git a/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs b/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs index 4b4819d..2a76bf9 100644 --- a/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs +++ b/MicroEngineerProject/MicroEngineer/Utilities/Utility.cs @@ -248,7 +248,7 @@ internal static bool ToggleGameInputOnControlInFocus(bool gameInputState, bool s { if (gameInputState) { - if (InputDisableWindowAbbreviation == GUI.GetNameOfFocusedControl() || InputDisableWindowName == GUI.GetNameOfFocusedControl()) + if (Manager.Instance.TextFieldNames.Contains(GUI.GetNameOfFocusedControl())) { GameManager.Instance.Game.Input.Disable(); return false; @@ -258,7 +258,7 @@ internal static bool ToggleGameInputOnControlInFocus(bool gameInputState, bool s } else { - if (InputDisableWindowAbbreviation != GUI.GetNameOfFocusedControl() && InputDisableWindowName != GUI.GetNameOfFocusedControl() || !showGuiFlight) + if (!Manager.Instance.TextFieldNames.Contains(GUI.GetNameOfFocusedControl()) || !showGuiFlight) { GameManager.Instance.Game.Input.Enable(); return true; @@ -288,7 +288,7 @@ internal static (int major, int minor, int patch)? GetModVersion(string modId) if (versionNumbers.Length == 3) int.TryParse(versionNumbers[2], out patchVersion); - Logger.LogInfo($"Space Warp version {majorVersion}.{minorVersion}.{patchVersion} detected."); + Logger.LogInfo($"{modId} version {majorVersion}.{minorVersion}.{patchVersion} detected."); return (majorVersion, minorVersion, patchVersion); } @@ -325,5 +325,12 @@ internal static bool IsModOlderThan(string modId, int major, int minor, int patc else return false; } + + public static bool AreRectsNear(Rect rect1, Rect rect2) + { + float distanceX = Mathf.Abs(rect1.center.x - rect2.center.x); + float distanceY = Mathf.Abs(rect1.center.y - rect2.center.y); + return (distanceX < rect1.width / 2 + rect2.width / 2 + 50f && distanceY < rect1.height / 2 + rect2.height / 2 + 50f); + } } } \ No newline at end of file diff --git a/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs index 9231152..f967eff 100644 --- a/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs +++ b/MicroEngineerProject/MicroEngineer/Windows/EntryWindow.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using UnityEngine; namespace MicroMod { @@ -36,6 +37,8 @@ internal class EntryWindow: BaseWindow [JsonProperty] internal bool IsEditable { get => MainWindow != MainWindow.Stage && MainWindow != MainWindow.StageInfoOAB; } + internal bool IsBeingDragged { get => FlightRect.Contains(Event.current.mousePosition); } + [JsonProperty] internal MainWindow MainWindow; diff --git a/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs b/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs index 1ce2215..ee9e26e 100644 --- a/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs +++ b/MicroEngineerProject/MicroEngineer/Windows/SettingsWIndow.cs @@ -7,6 +7,12 @@ internal class SettingsWIndow : BaseWindow { [JsonProperty] internal Theme ActiveTheme { get; set; } + [JsonProperty] + private bool snapWindows = true; + internal bool SnapWindows { get => snapWindows; set => snapWindows = value; } + [JsonProperty] + private float snapDistance = 20f; + internal float SnapDistance { get => snapDistance; set => snapDistance = value; } internal void LoadSettings() { diff --git a/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs b/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs index 4d6cb09..80bb951 100644 --- a/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs +++ b/MicroEngineerProject/MicroEngineer/Windows/StageWindow.cs @@ -23,6 +23,10 @@ internal void DrawWindow(UI ui) GUILayout.Height(0) ); + var settings = Manager.Instance.Windows.Find(w => w is SettingsWIndow) as SettingsWIndow; + if (settings.SnapWindows && this.IsBeingDragged) + ui.HandleSnapping(this); + this.FlightRect.position = Utility.ClampToScreen(this.FlightRect.position, this.FlightRect.size); } else diff --git a/README.md b/README.md index 5b89e49..049ca2f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Micro Engineer - a KSP2 plugin Displays useful in-flight information about your vessel, your orbital and surface parameters and many other things. -![Micro Engineer](https://i.imgur.com/I7mZ4oQ.png) +![Micro Engineer](https://i.imgur.com/Gz7PgWL.png) # Links * Spacedock: https://spacedock.info/mod/3282/Micro%20Engineer @@ -9,7 +9,7 @@ Displays useful in-flight information about your vessel, your orbital and surfac * Contact: [KSP 2 Modding Society](https://discord.com/channels/1078696971088433153/1080340366995239004) # Description -A (heavily) KER inspired little mod to give you some additional information on your missions. +A (heavily) KER inspired mod to give you some additional information on your missions. You can enable and disable individual sections and pop them out into their own window or create your own window containing only the information you want to see. diff --git a/Staging/BepInEx/plugins/micro_engineer/swinfo.json b/Staging/BepInEx/plugins/micro_engineer/swinfo.json index 3940bd7..4c1b58f 100644 --- a/Staging/BepInEx/plugins/micro_engineer/swinfo.json +++ b/Staging/BepInEx/plugins/micro_engineer/swinfo.json @@ -1,16 +1,17 @@ { + "spec": "1.2", "mod_id": "micro_engineer", "author": "Micrologist, Falki", "name": "Micro Engineer", "description": "Get in-flight and VAB information about your current vessel", "source": "https://github.com/Micrologist/MicroEngineer", - "version": "1.0.3", + "version": "1.1.0", "version_check": "https://raw.githubusercontent.com/Micrologist/MicroEngineer/main/Staging/BepInEx/plugins/micro_engineer/swinfo.json", "dependencies": [ { "id": "SpaceWarp", "version": { - "min": "1.0.1", + "min": "1.1.0", "max": "*" } }