From e58936477a8f107706750fef7f9894ba2576b75c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 25 Sep 2020 11:06:28 +0900 Subject: [PATCH 001/150] Document ELExtractor --- Documentation/EL_Manual.lyx | 181 ++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/Documentation/EL_Manual.lyx b/Documentation/EL_Manual.lyx index f8d8ce07..01460171 100644 --- a/Documentation/EL_Manual.lyx +++ b/Documentation/EL_Manual.lyx @@ -5460,6 +5460,187 @@ ELExtractor \begin_layout Standard Extracts resources from the environment. + Note that +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + works with both the stock resource system and with Kethane (auto-detected + if installed). + Can (with a little work +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +Currently, this would require modifying EL's source to search for implementers + of IResourceProvider instead of simply adding the stock and Kethane (if + installed) providers. +\end_layout + +\end_inset + +) be extended to support other resource providers. + All supported providers are treated equally in that the amount of resource + extracted from a provider is based on that provider's contribution to the + available resource at the location of extractor part's ground-hit location. + For example with Kethane installed, EL's auger will extract +\noun on +MetalOre +\noun default + from a Kethane deposit at a rate slightly lower than specified by +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +Rate +\end_layout + +\end_inset + + in the module files because the stock resource system will provide a certain + amount (based on concentration) as well, resulting in the total rate of + extraction being as specified, but if the auger misses a Kethane-based + deposit, the extraction rate will be determined by concentration multiplied + by the specified rate. +\end_layout + +\begin_layout Paragraph +Model Requirements +\end_layout + +\begin_layout Standard +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + requires the model to have a head transform (goes into the ground) and + a tail transform (does not go into the ground). + The transforms are used to do a physics ray-cast to determine both whether + the extractor has ground contact and the exact location of that contact. + The head transform must be outside any colliders in order to allow it into + the ground (visual mesh that penetrates the ground poses no problem). + The tail transform may be either inside or outside any colliders, but inside + is recommended to ensure that it cannot go into the ground. + The transforms may be animated: the ray-cast is performed each frame. +\end_layout + +\begin_layout Paragraph +Part Requirements +\end_layout + +\begin_layout Standard +None. +\end_layout + +\begin_layout Paragraph +Module Fields +\end_layout + +\begin_layout Description +EVARange Adjust the range (in meters) from which an EVA kerbal can activate + or deactivate the extractor. + Default is +\begin_inset Formula $1.5m$ +\end_inset + +. +\end_layout + +\begin_layout Description +ResourceName The name of the resource to extract. + Required. +\end_layout + +\begin_layout Description +Rate The flow rate of the extractor, in +\begin_inset Formula $u/s$ +\end_inset + + (resource units/second). + Defaults to +\begin_inset Formula $0$ +\end_inset + +. +\end_layout + +\begin_layout Description +flowMode How the extracted resource is distributed through the extractor + vessel. + Defaults to +\noun on + +\begin_inset Flex Code +status open + +\begin_layout Plain Layout + +\noun on +ALL_VESSEL +\end_layout + +\end_inset + +. +\end_layout + +\begin_layout Description +HeadTransform The name of the model transform used as the target of the + ray-cast used to detect ground contact. + This is the point of the model that needs to be in the ground for the part + to be considered in contact with the ground. +\end_layout + +\begin_layout Description +TailTransform The name of the model transform used as the source of the + ray-cast used to detect ground contact. + This is the point of the model that needs to be out of the ground for the + part to be considered in contact with the ground. +\end_layout + +\begin_layout Description +INPUT_RESOURCE{} Note that this is a node. + This is as per the stock resource extraction module ( +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +ELExtractor +\end_layout + +\end_inset + + is derives from +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +BaseDrill +\end_layout + +\end_inset + +, so many of +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +BaseDrill +\end_layout + +\end_inset + +'s fields and nodes are relevant). \end_layout \begin_layout Subsubsection From a65f5ad5ed133a8431b58ca32431f0b8db0f3c06 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 27 Sep 2020 15:04:09 +0900 Subject: [PATCH 002/150] Start using KodeUI KodeUI is added as a submodule and its core code symlinked into the Source directory for convenience. This marks the beginning of EL's UI overhaul --- .gitmodules | 3 +++ KodeUI | 1 + README.txt | 15 ++++++++++++++- Source/KodeUI | 1 + Source/Makefile | 5 ++++- 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .gitmodules create mode 160000 KodeUI create mode 120000 Source/KodeUI diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..f97e855f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "KodeUI"] + path = KodeUI + url = https://github.com/sarbian/KodeUI.git diff --git a/KodeUI b/KodeUI new file mode 160000 index 00000000..2adb6290 --- /dev/null +++ b/KodeUI @@ -0,0 +1 @@ +Subproject commit 2adb6290e99233e8faec16cadc74a3bc13cf73bd diff --git a/README.txt b/README.txt index e2e907c0..9187856f 100644 --- a/README.txt +++ b/README.txt @@ -64,7 +64,20 @@ Mods considered essential for getting the most out of EL: o Infernal Robotics. Makes it easier to move things around. http://forum.kerbalspaceprogram.com/threads/37707 -Please report all issues at https://github.com/taniwha-qf/Extraplanetary-Launchpads/issues +Please report all issues at +https://github.com/taniwha-qf/Extraplanetary-Launchpads/issues Many resource containers use HexCans by Greys (https://github.com/Greys0/HexCans). + +Notes for building: +Note that EL depends on KodeUI: https://github.com/sarbian/KodeUI.git +However, KodeUI is included as a git submodule. Use + + git submodule init + git submodule update + +to get started and refer to the `git submodule --help` (or +https://git-scm.com/book/en/v2/Git-Tools-Submodules) for further +details. However, the tree has been set up to "just work" once +submodules have been updated. diff --git a/Source/KodeUI b/Source/KodeUI new file mode 120000 index 00000000..fcbe2b4d --- /dev/null +++ b/Source/KodeUI @@ -0,0 +1 @@ +../KodeUI/KodeUI-Unity/Assets/KodeUI \ No newline at end of file diff --git a/Source/Makefile b/Source/Makefile index 8421f515..7f80026c 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -93,6 +93,8 @@ EL_FILES := \ Settings.cs \ $e +include KodeUI/KodeUI.inc + RESGEN2 := resgen2 CSC := csc CSCFLAGS := -highentropyva- -noconfig -nostdlib+ -t:library -optimize -warnaserror -debug @@ -135,10 +137,11 @@ UNITY := \ -r:UnityEngine.AnimationModule.dll \ -r:UnityEngine.CoreModule.dll \ -r:UnityEngine.PhysicsModule.dll \ + -r:UnityEngine.Physics2DModule.dll \ -r:UnityEngine.InputLegacyModule.dll \ $e -bin/Launchpad.dll: ${EL_FILES} +bin/Launchpad.dll: ${EL_FILES} ${KodeUI} @mkdir -p bin ${CSC} ${CSCFLAGS} ${SYSTEM} ${KSP} ${UNITY} -out:$@ $^ From 275f74a08c667d7c79f7aa7ced37866c71aee377 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 1 Oct 2020 19:01:03 +0900 Subject: [PATCH 003/150] Begin implementing the new UI for the build window --- KodeUI | 2 +- Source/GUI/BuildWindow.cs | 17 +++ Source/Makefile | 5 + Source/UI/CraftControl.cs | 313 ++++++++++++++++++++++++++++++++++++++ Source/UI/Localization.cs | 40 +++++ Source/UI/MainWindow.cs | 70 +++++++++ Source/UI/PadControl.cs | 209 +++++++++++++++++++++++++ Source/UI/StatusBar.cs | 172 +++++++++++++++++++++ 8 files changed, 827 insertions(+), 1 deletion(-) create mode 100644 Source/UI/CraftControl.cs create mode 100644 Source/UI/Localization.cs create mode 100644 Source/UI/MainWindow.cs create mode 100644 Source/UI/PadControl.cs create mode 100644 Source/UI/StatusBar.cs diff --git a/KodeUI b/KodeUI index 2adb6290..14a253b8 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 2adb6290e99233e8faec16cadc74a3bc13cf73bd +Subproject commit 14a253b89e0dc4f733c0532f4b788cb2951bbc3f diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs index 13f91202..93f79e4a 100644 --- a/Source/GUI/BuildWindow.cs +++ b/Source/GUI/BuildWindow.cs @@ -21,6 +21,8 @@ You should have received a copy of the GNU General Public License using System.Linq; using UnityEngine; +using KodeUI; + using KSP.IO; using KSP.UI.Screens; @@ -48,6 +50,7 @@ public class ELBuildWindow : MonoBehaviour static Texture2D flagTexture; List launchpads; + Vessel vessel; ELVesselWorkNet worknet; DropDownList pad_list; ELBuildControl control; @@ -227,6 +230,8 @@ void onVesselChange (Vessel v) { BuildPadList (v); UpdateGUIState (); + vessel = v; + mainWindow.SetVessel(vessel); } void onVesselWasModified (Vessel v) @@ -245,6 +250,7 @@ static public void updateCurrentPads() { void UpdateGUIState () { + bool old = enabled; enabled = !hide_ui && launchpads != null && gui_enabled; if (control != null) { control.builder.Highlight (enabled && highlight_pad); @@ -258,6 +264,13 @@ void UpdateGUIState () p.builder.UpdateMenus (enabled && p == control); } } + if (!mainWindow) { + mainWindow = UIKit.CreateUI (appCanvas.transform as RectTransform, "ELMainWindow"); + } + if (old != enabled) { + mainWindow.gameObject.SetActive(enabled); + mainWindow.SetVessel (vessel); + } } void UpdateFlagTexture () @@ -291,8 +304,12 @@ void onShowUI () UpdateGUIState (); } + Canvas appCanvas; + ELMainWindow mainWindow; + void Awake () { + appCanvas = DialogCanvasUtil.DialogCanvas; instance = this; GameEvents.onVesselChange.Add (onVesselChange); GameEvents.onVesselWasModified.Add (onVesselWasModified); diff --git a/Source/Makefile b/Source/Makefile index 7f80026c..d8a2531d 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -74,6 +74,11 @@ EL_FILES := \ Recycler/Recycler.cs \ Recycler/StateMachine.cs \ Target/Target.cs \ + UI/CraftControl.cs \ + UI/Localization.cs \ + UI/MainWindow.cs \ + UI/PadControl.cs \ + UI/StatusBar.cs \ Workshop/ConstructionSkill.cs \ Workshop/ProtoWorkSink.cs \ Workshop/VesselWorkNet.cs \ diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs new file mode 100644 index 00000000..21c53938 --- /dev/null +++ b/Source/UI/CraftControl.cs @@ -0,0 +1,313 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftControl : Layout + { + Layout selectedCraft; + + Sprite flagTexture; + + UIButton selectCraftButton; + UIButton selectFlagButton; + UIButton reloadButton; + UIButton clearButton; + + UIText craftName; + UIText craftBoM; + UIImage craftThumb; + + ELBuildControl control; + + FlagBrowser flagBrowser; + ELCraftBrowser craftList; + + static FlagBrowser _flagBrowserPrefab; + static FlagBrowser flagBrowserPrefab + { + get { + if (!_flagBrowserPrefab) { + var fbObj = AssetBase.GetPrefab ("FlagBrowser"); + _flagBrowserPrefab = fbObj.GetComponent (); + } + return _flagBrowserPrefab; + } + } + + public override void CreateUI() + { + base.CreateUI (); + + KodeUI.ScrollView scrollview; + UIScrollbar scrollbar; + UIText overflowText; + + Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Anchor(AnchorPresets.HorStretchTop) + .FlexibleLayout (true,false) + .Add (out selectCraftButton) + .Text (ELLocalization.SelectCraft) + .OnClick (SelectCraft) + .FlexibleLayout (true, true) + .Finish () + .Add (out selectFlagButton) + .Image (flagTexture) + .OnClick (SelectFlag) + .PreferredSize (48, 30) + .Finish () + .Add (out reloadButton) + .Text (ELLocalization.Reload) + .OnClick (Reload) + .Finish () + .Add (out clearButton) + .Text (ELLocalization.Clear) + .OnClick (Clear) + .Finish () + .Finish () + .Add() + .Background("KodeUI/Default/background") + .BackgroundColor(UnityEngine.Color.white) + .Vertical() + .Padding(8) + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .Anchor(AnchorPresets.HorStretchTop) + .FlexibleLayout(true,true) + .PreferredHeight(300) + .Add (out selectedCraft) + .Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .FlexibleLayout(true,false) + .Add () + .Text (ELLocalization.SelectedCraft) + .Finish () + .Add (out craftName) + .Finish () + .Finish () + .Add (out scrollview) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Add (out scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish (); + + scrollview.VerticalScrollbar = scrollbar; + scrollview.Viewport.FlexibleLayout (true, true); + scrollview.Content + .VertiLink () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .WidthDelta(0) + // resources + .Add () + .Horizontal () + .ControlChildSize (true, false) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .FlexibleLayout (true, false) + .Add (out craftBoM) + .Alignment (TextAlignmentOptions.TopLeft) + .FlexibleLayout (true, false) + .SizeDelta (0, 256) + .Finish () + .Add (out craftThumb) + .Anchor (AnchorPresets.TopLeft) + .Pivot (PivotPresets.TopLeft) + .SizeDelta (256, 256) + .MinSize (256, 256) + .Finish () + .Finish () + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, false) + .Add (out overflowText) + .Alignment (TextAlignmentOptions.TopLeft) + .FlexibleLayout (true, false) + .Finish() + .Finish () + .Finish (); + + craftBoM.tmpText.overflowMode = TextOverflowModes.Linked; + craftBoM.tmpText.linkedTextComponent = overflowText.tmpText; + } + + void craftSelectComplete (string filename, + CraftBrowserDialog.LoadType lt) + { + control.craftType = craftList.craftType; + craftList = null; + + control.LoadCraft (filename, control.flagname); + + bool enable = control.craftConfig != null; + selectCraftButton.interactable = true; + reloadButton.interactable = enable; + clearButton.interactable = enable; + } + + void craftSelectCancel () + { + craftList = null; + selectCraftButton.interactable = true; + } + + void SelectCraft () + { + string path = HighLogic.SaveFolder; + + craftList = ELCraftBrowser.Spawn (control.craftType, + path, + craftSelectComplete, + craftSelectCancel, + false); + selectCraftButton.interactable = false; + } + + void OnFlagCancel () + { + flagBrowser = null; + selectFlagButton.interactable = true; + } + + static Sprite MakeSprite (Texture2D tex) + { + var rect = new Rect (0, 0, tex.width, tex.height); + var pivot = new Vector2 (0.5f, 0.5f); + float pixelsPerUnity = 100; + uint extrude = 0; + var type = SpriteMeshType.Tight; + var border = Vector4.zero; + + return UnityEngine.Sprite.Create (tex, rect, pivot, pixelsPerUnity, + extrude, type, border); + } + + void OnFlagSelected (FlagBrowser.FlagEntry selected) + { + Destroy (flagTexture); + + control.flagname = selected.textureInfo.name; + UpdateFlag (); + flagBrowser = null; + selectFlagButton.interactable = true; + } + + void SelectFlag () + { + flagBrowser = Instantiate (flagBrowserPrefab); + flagBrowser.OnDismiss = OnFlagCancel; + flagBrowser.OnFlagSelected = OnFlagSelected; + selectFlagButton.interactable = false; + } + + void Reload () + { + control.LoadCraft (control.filename, control.flagname); + } + + void Clear () + { + control.UnloadCraft (); + reloadButton.interactable = false; + clearButton.interactable = false; + } + + public override void Style () + { + base.Style (); + } + + void UpdateFlag () + { + if (control != null) { + if (String.IsNullOrEmpty (control.flagname)) { + control.flagname = control.builder.part.flagURL; + } + var tex = GameDatabase.Instance.GetTexture (control.flagname, false); + flagTexture = MakeSprite (tex); + selectFlagButton.Image (flagTexture); + } + } + + void UpdateCraftInfo () + { + if (control != null) { + bool enable = control.craftConfig != null; + selectedCraft.gameObject.SetActive (enable); + + craftName.Text (control.craftName); + if (control.craftBoM != null || control.CreateBoM ()) { + craftBoM.Text(String.Join ("\n", control.craftBoM)); + } + } else { + selectedCraft.gameObject.SetActive (false); + } + } + + public void SetControl (ELBuildControl control) + { + this.control = control; + + if (control != null) { + UpdateFlag (); + UpdateCraftInfo (); + selectCraftButton.interactable = true; + selectFlagButton.interactable = true; + bool enable = control.craftConfig != null; + reloadButton.interactable = enable; + clearButton.interactable = enable; + } else { + selectCraftButton.interactable = false; + selectFlagButton.interactable = false; + reloadButton.interactable = false; + clearButton.interactable = false; + } + } + } +} diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs new file mode 100644 index 00000000..a619fdb1 --- /dev/null +++ b/Source/UI/Localization.cs @@ -0,0 +1,40 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + public static class ELLocalization + { + public static string Productivity { get; } = "Productivity:"; + public static string SelectCraft { get; } = "Select Craft"; + public static string SelectedCraft { get; } = "Selected Craft"; + public static string Reload { get; } = "Reload"; + public static string Clear { get; } = "Clear"; + public static string Pad { get; } = "pad"; + } +} diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs new file mode 100644 index 00000000..83a0f3d4 --- /dev/null +++ b/Source/UI/MainWindow.cs @@ -0,0 +1,70 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + public class ELMainWindow : Window + { + ELStatusBar statusBar; + ELPadControl padControl; + ELCraftControl craftControl; + + public override void CreateUI() + { + base.CreateUI (); + Title (ELVersionReport.GetVersion ()) + .Vertical() + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .PreferredSizeFitter(true, true) + .Anchor(AnchorPresets.MiddleCenter) + .Pivot(PivotPresets.TopLeft) + .PreferredWidth(695) + + .Add(out statusBar, "StatusBar") + .Finish() + .Add(out padControl, "PadControl") + .Finish() + .Add(out craftControl, "CraftControl") + .Finish() + .Finish(); + padControl.craftControl = craftControl; + } + + public override void Style () + { + base.Style (); + } + + public void SetVessel (Vessel vessel) + { + statusBar.SetVessel (vessel); + padControl.SetVessel (vessel); + } + } +} diff --git a/Source/UI/PadControl.cs b/Source/UI/PadControl.cs new file mode 100644 index 00000000..b10f8e0e --- /dev/null +++ b/Source/UI/PadControl.cs @@ -0,0 +1,209 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using TMPro; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + using OptionData = TMP_Dropdown.OptionData; + + public class ELPadControl : LayoutAnchor + { + Vessel vessel; + ELVesselWorkNet worknet; + ELBuildControl _control; + public ELBuildControl control + { + get { return _control; } + private set { + _control = value; + if (_craftControl != null) { + _craftControl.SetControl (_control); + } + } + } + + List padNames; + List padControls; + + UIDropdown padSelector; + UIToggle highlightPad; + + ELCraftControl _craftControl; + public ELCraftControl craftControl + { + get { return _craftControl; } + set { + _craftControl = value; + if (_craftControl != null) { + _craftControl.SetControl (control); + } + } + } + + public override void CreateUI() + { + base.CreateUI (); + + Vector2 leftMin = new Vector2 (0, 0); + Vector2 leftMax = new Vector2 (0.5f, 1); + Vector2 rightMin = new Vector2 (0.5f, 0); + Vector2 rightMax = new Vector2 (1, 1); + + this + .DoPreferredHeight (true) + .DoMinHeight (true) + .FlexibleLayout (true, false) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (leftMin, leftMax) + .SizeDelta (0, 0) + .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) + .Color(UnityEngine.Color.blue) + .Add (out padSelector, "PadSelector") + .OnValueChanged (SelectPad) + .FlexibleLayout (true, true) + .Finish () + .Add (out highlightPad, "HighlightPad") + .FlexibleLayout (false, true) + .PreferredSize (25, 25) + .Finish () + .Finish () + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (rightMin, rightMax) + .SizeDelta (0, 0) + .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) + .Color(UnityEngine.Color.red) + // XXX pad / survey controls + .Finish () + .Finish (); + + padNames = new List (); + padControls = new List (); + } + + public override void Style () + { + } + + void SelectPad (int index) + { + control = padControls[index]; + } + + static ELVesselWorkNet FindWorkNet (Vessel v) + { + for (int i = 0; i < v.vesselModules.Count; i++) { + var worknet = v.vesselModules[i] as ELVesselWorkNet; + if (worknet != null) { + return worknet; + } + } + return null; + } + + static ELBuildControl FindControl (Vessel v, uint id) + { + Part part = v[id]; + if (part != null) { + var pad = part.FindModuleImplementing (); + if (pad != null) { + return pad.control; + } + } + return null; + } + + void BuildPadList () + { + padNames.Clear (); + padControls.Clear (); + worknet = null; + control = null; + if (!vessel) { + return; + } + + var pads = vessel.FindPartModulesImplementing (); + int control_index = -1; + + if (pads.Count < 1) { + padSelector.interactable = false; + } else { + worknet = FindWorkNet (vessel); + if (worknet != null) { + control = FindControl (vessel, worknet.selectedPad); + } + + for (int i = 0; i < pads.Count; i++) { + if (String.IsNullOrEmpty (pads[i].Name)) { + padNames.Add (new OptionData ($"{ELLocalization.Pad}-{i}")); + } else { + padNames.Add (new OptionData (pads[i].Name)); + } + padControls.Add (pads[i].control); + if (control == pads[i].control) { + control_index = i; + } + } + } + padSelector.Options (padNames); + padSelector.SetValueWithoutNotify (control_index); + } + + public void SetVessel (Vessel vessel) + { + this.vessel = vessel; + BuildPadList (); + } + + void onVesselWasModified (Vessel v) + { + if (v == vessel) { + } + } + + protected override void OnEnable () + { + base.OnEnable (); + GameEvents.onVesselWasModified.Add (onVesselWasModified); + } + + protected override void OnDisable () + { + base.OnDisable (); + GameEvents.onVesselWasModified.Remove (onVesselWasModified); + } + } +} diff --git a/Source/UI/StatusBar.cs b/Source/UI/StatusBar.cs new file mode 100644 index 00000000..f5d47a17 --- /dev/null +++ b/Source/UI/StatusBar.cs @@ -0,0 +1,172 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using TMPro; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + public class ELStatusBar : Layout + { + Vessel vessel; + ELVesselWorkNet worknet; + + UIText vesselName; + UIText situation; + UIText productivityLabel; + UIText productivity; + + public override void CreateUI() + { + base.CreateUI (); + Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .FlexibleLayout (true,false) + .Add (out vesselName, "Name") + .Alignment (TextAlignmentOptions.Left) + .FlexibleLayout (false, true) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add (out situation, "Situation") + .Alignment (TextAlignmentOptions.Left) + .FlexibleLayout (false, true) + .Finish () + .Add () + .PreferredWidth (10) + .Finish() + .Add ("Productivity") + .Horizontal() + .Padding (3, 3, 3, 3) + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Add (out productivityLabel, "Label") + .Text (ELLocalization.Productivity) + .Finish() + .Add () + .PreferredWidth (3) + .Finish() + .Add (out productivity, "Value") + .Text (ELLocalization.Productivity) + .Alignment(TextAlignmentOptions.Right) + .MinSize (75, -1) + .PreferredSize (75, -1) + .Finish() + .Finish(); + } + + public override void Style () + { + base.Style (); + } + + void UpdateVesselName () + { + if (vessel) { + vesselName.Text (vessel.vesselName); + } else { + vesselName.Text ("----"); + } + } + + void UpdateSituation () + { + if (vessel) { + situation.Text (vessel.situation.displayDescription ()); + } else { + situation.Text ("----"); + } + } + + void UpdateProductivity () + { + if (worknet != null) { + double p = worknet.Productivity; + Color c = UnityEngine.Color.green; //FIXME styles + if (p <= 0) { + c = UnityEngine.Color.red; //FIXME styles + } else if (p < 1) { + c = UnityEngine.Color.yellow; //FIXME styles + } + productivityLabel.Color (c).Style(); + productivity.Text($"{p:G3}").Color (c).Style(); + } else { + Color c = UnityEngine.Color.red; //FIXME styles + productivityLabel.Color (c).Style(); + productivity.Text("----").Color (c).Style(); + } + } + + public void SetVessel (Vessel vessel) + { + this.vessel = vessel; + if (vessel) { + worknet = vessel.FindVesselModuleImplementing (); + } else { + worknet = null; + } + UpdateVesselName (); + UpdateSituation (); + UpdateProductivity (); + } + + void onVesselRename (GameEvents.HostedFromToAction vs) + { + if (vs.host == vessel) { + UpdateVesselName (); + } + } + + void onVesselSituationChange (GameEvents.HostedFromToAction vs) + { + if (vs.host == vessel) { + UpdateSituation (); + } + } + + protected override void OnEnable () + { + base.OnEnable (); + GameEvents.onVesselSituationChange.Add (onVesselSituationChange); + GameEvents.onVesselRename.Add (onVesselRename); + } + + protected override void OnDisable () + { + base.OnDisable (); + GameEvents.onVesselSituationChange.Remove (onVesselSituationChange); + GameEvents.onVesselRename.Remove (onVesselRename); + } + + void Update () + { + UpdateProductivity (); + } + } +} From 385e1d27dedad606ac07d5d489011d4d4927b11e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 01:42:35 +0900 Subject: [PATCH 004/150] Silence log errors about missing modules In particular, ModuleRestockLaunchClamp when ReStock isn't installed. --- Source/BuildControl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index c8c0e885..c7139f1d 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -603,7 +603,7 @@ void RotateLaunchClamps (ShipConstruct ship) elc[j].RotateTower (); } if (elc.Count < 1) { - if (p.Modules["ModuleRestockLaunchClamp"] != null) { + if (p.Modules.GetModule("ModuleRestockLaunchClamp") != null) { p.SendMessage("RotateTower", SendMessageOptions.DontRequireReceiver); } } @@ -624,7 +624,7 @@ void EnableExtendingLaunchClamps (ShipConstruct ship) // ReplaceLaunchClamps will not do any replacement because // the module uses a different name. Thus this will pick up // the ReStock module. - var lc = p.Modules["ModuleRestockLaunchClamp"]; + var lc = p.Modules.GetModule("ModuleRestockLaunchClamp"); if (lc != null) { (lc as LaunchClamp).EnableExtension (); } From 985ac8898ffb6497d1164faacac958b379db30d3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 08:06:23 +0900 Subject: [PATCH 005/150] Implement BuildResourceSet as ICollection properly This fixes the inability to use var in a foreach. Turns out I didn't actually need it, but it's nice to have and I learned a bit more c#. --- Source/Recipes/BuildResourceSet.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Source/Recipes/BuildResourceSet.cs b/Source/Recipes/BuildResourceSet.cs index 7a95367e..f415b08f 100644 --- a/Source/Recipes/BuildResourceSet.cs +++ b/Source/Recipes/BuildResourceSet.cs @@ -22,7 +22,7 @@ You should have received a copy of the GNU General Public License using UnityEngine; namespace ExtraplanetaryLaunchpads { - public class BuildResourceSet : ICollection + public class BuildResourceSet : ICollection { Dictionary resources; @@ -47,14 +47,26 @@ public object SyncRoot } } - public void CopyTo (Array array, int index) + public bool IsReadOnly { get { return false; } } + + public bool Contains (BuildResource res) + { + return resources.ContainsKey(res.name); + } + + public void CopyTo (BuildResource []array, int index) { foreach (var res in resources.Values) { array.SetValue (res, index++); } } - public IEnumerator GetEnumerator () + IEnumerator IEnumerable.GetEnumerator () + { + return resources.Values.GetEnumerator (); + } + + public IEnumerator GetEnumerator () { return resources.Values.GetEnumerator (); } @@ -80,9 +92,9 @@ public void Add (BuildResource res) } } - public void Remove (BuildResource res) + public bool Remove (BuildResource res) { - resources.Remove (res.name); + return resources.Remove (res.name); } public void Clear () From db219e3021661e47f6576385f24dcf4be710385b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 08:08:51 +0900 Subject: [PATCH 006/150] Rename EL's ScrollView This avoids conflicts with KodeUI's, and it will go away soon anyway. --- Source/GUI/BuildWindow.cs | 2 +- Source/GUI/ResourceWindow.cs | 2 +- Source/GUI/ScrollView.cs | 6 +++--- Source/GUI/ShipInfo.cs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs index 93f79e4a..03611be1 100644 --- a/Source/GUI/BuildWindow.cs +++ b/Source/GUI/BuildWindow.cs @@ -42,7 +42,7 @@ public class ELBuildWindow : MonoBehaviour static double minimum_alarm_time = 60; static ELCraftBrowser craftlist = null; - static ScrollView resScroll = new ScrollView (680,300); + static ELScrollView resScroll = new ELScrollView (680,300); static FlagBrowser flagBrowserPrefab; static FlagBrowser flagBrowser; diff --git a/Source/GUI/ResourceWindow.cs b/Source/GUI/ResourceWindow.cs index cdb68082..355be9e2 100644 --- a/Source/GUI/ResourceWindow.cs +++ b/Source/GUI/ResourceWindow.cs @@ -37,7 +37,7 @@ public class ELResourceWindow : MonoBehaviour static bool gui_enabled = false; static Rect windowpos; static bool link_lfo_sliders = true; - static ScrollView resscroll = new ScrollView (680, 300); + static ELScrollView resscroll = new ELScrollView (680, 300); static GUILayoutOption toggleWidth = GUILayout.Width (80); public enum XferState { diff --git a/Source/GUI/ScrollView.cs b/Source/GUI/ScrollView.cs index 7805fbec..94ce3c79 100644 --- a/Source/GUI/ScrollView.cs +++ b/Source/GUI/ScrollView.cs @@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ScrollView + public class ELScrollView { public delegate void ScrollFunc (); public ScrollFunc Begin { get; private set; } @@ -32,7 +32,7 @@ public class ScrollView GUILayoutOption width; GUILayoutOption height; - public ScrollView (int width, int height) + public ELScrollView (int width, int height) { this.width = GUILayout.Width (width); this.height = GUILayout.Height (height); @@ -41,7 +41,7 @@ public ScrollView (int width, int height) End = EndWidthHeight; } - public ScrollView (int height) + public ELScrollView (int height) { this.height = GUILayout.Height (height); diff --git a/Source/GUI/ShipInfo.cs b/Source/GUI/ShipInfo.cs index 56e1336d..893453c0 100644 --- a/Source/GUI/ShipInfo.cs +++ b/Source/GUI/ShipInfo.cs @@ -33,8 +33,8 @@ public class ELShipInfo : MonoBehaviour int parts_count; public BuildCost buildCost; CostReport cashed_cost; - ScrollView reqScroll = new ScrollView (100); - ScrollView optScroll = new ScrollView (100); + ELScrollView reqScroll = new ELScrollView (100); + ELScrollView optScroll = new ELScrollView (100); public static void ToggleGUI () { @@ -197,7 +197,7 @@ private void MassLabel (string title, double mass) private void ResourcePanel (string title, List resources, - ScrollView scroll) + ELScrollView scroll) { GUILayout.Label (title + ":"); GUILayout.BeginVertical (GUILayout.Height (100)); From cfa2154742f5d614a9f2f3d61e24e9ce322731a3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 08:12:13 +0900 Subject: [PATCH 007/150] Get the craft info panel working This includes the thumbnail view (not stock, probably have the path wrong) and the required resources. --- KodeUI | 2 +- Source/GUI/BuildWindow.cs | 3 + Source/Makefile | 2 + Source/UI/CraftControl.cs | 111 ++++++++++++++++++--- Source/UI/Localization.cs | 1 + Source/UI/ResourceDisplay.cs | 182 +++++++++++++++++++++++++++++++++++ Source/lib/Utils.cs | 17 +++- 7 files changed, 302 insertions(+), 16 deletions(-) create mode 100644 Source/UI/ResourceDisplay.cs diff --git a/KodeUI b/KodeUI index 14a253b8..a2bc95c0 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 14a253b89e0dc4f733c0532f4b788cb2951bbc3f +Subproject commit a2bc95c0494a2089e6493b92f91541bb7761b9ca diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs index 03611be1..cfa8a96e 100644 --- a/Source/GUI/BuildWindow.cs +++ b/Source/GUI/BuildWindow.cs @@ -327,6 +327,9 @@ void OnDestroy () GameEvents.onHideUI.Remove (onHideUI); GameEvents.onShowUI.Remove (onShowUI); GameEvents.onVesselSwitchingToUnloaded.Remove (VMSaveHack); + if (mainWindow) { + Destroy (mainWindow); + } } float ResourceLine (string label, string resourceName, float fraction, diff --git a/Source/Makefile b/Source/Makefile index d8a2531d..cf68f1f3 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -78,6 +78,7 @@ EL_FILES := \ UI/Localization.cs \ UI/MainWindow.cs \ UI/PadControl.cs \ + UI/ResourceDisplay.cs \ UI/StatusBar.cs \ Workshop/ConstructionSkill.cs \ Workshop/ProtoWorkSink.cs \ @@ -144,6 +145,7 @@ UNITY := \ -r:UnityEngine.PhysicsModule.dll \ -r:UnityEngine.Physics2DModule.dll \ -r:UnityEngine.InputLegacyModule.dll \ + -r:UnityEngine.ImageConversionModule.dll \ $e bin/Launchpad.dll: ${EL_FILES} ${KodeUI} diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs index 21c53938..52430e25 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftControl.cs @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License . */ using System; +using System.IO; using System.Reflection; using System.Collections.Generic; using System.Linq; @@ -26,13 +27,12 @@ You should have received a copy of the GNU General Public License using KodeUI; using KSP.IO; -using KSP.UI.Screens; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; namespace ExtraplanetaryLaunchpads { public class ELCraftControl : Layout { - Layout selectedCraft; Sprite flagTexture; @@ -41,6 +41,21 @@ public class ELCraftControl : Layout UIButton reloadButton; UIButton clearButton; + struct ResourcePair + { + public readonly BuildResource resource; + public readonly ELResourceDisplay display; + public ResourcePair (BuildResource resource, ELResourceDisplay display) + { + this.resource = resource; + this.display = display; + } + } + + ScrollView craftView; + Layout selectedCraft; + Layout resourceList; + List requiredResources; UIText craftName; UIText craftBoM; UIImage craftThumb; @@ -50,6 +65,8 @@ public class ELCraftControl : Layout FlagBrowser flagBrowser; ELCraftBrowser craftList; + static Texture2D genericCraftThumb; + static FlagBrowser _flagBrowserPrefab; static FlagBrowser flagBrowserPrefab { @@ -64,9 +81,13 @@ static FlagBrowser flagBrowserPrefab public override void CreateUI() { + if (!genericCraftThumb) { + genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); + } + requiredResources = new List (); + base.CreateUI (); - KodeUI.ScrollView scrollview; UIScrollbar scrollbar; UIText overflowText; @@ -117,10 +138,13 @@ public override void CreateUI() .Add () .Text (ELLocalization.SelectedCraft) .Finish () + .Add() + .MinSize(15,-1) + .Finish() .Add (out craftName) .Finish () .Finish () - .Add (out scrollview) + .Add (out craftView) .Horizontal (false) .Vertical (true) .Horizontal() @@ -133,16 +157,22 @@ public override void CreateUI() .Finish () .Finish (); - scrollview.VerticalScrollbar = scrollbar; - scrollview.Viewport.FlexibleLayout (true, true); - scrollview.Content + craftView.VerticalScrollbar = scrollbar; + craftView.Viewport.FlexibleLayout (true, true); + craftView.Content .VertiLink () .ControlChildSize (true, true) .ChildForceExpand (false, false) .Anchor (AnchorPresets.HorStretchTop) .PreferredSizeFitter(true, false) .WidthDelta(0) - // resources + .Add (out resourceList) + .Vertical() + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () .Add () .Horizontal () .ControlChildSize (true, false) @@ -177,8 +207,7 @@ public override void CreateUI() craftBoM.tmpText.linkedTextComponent = overflowText.tmpText; } - void craftSelectComplete (string filename, - CraftBrowserDialog.LoadType lt) + void craftSelectComplete (string filename, CBDLoadType lt) { control.craftType = craftList.craftType; craftList = null; @@ -189,6 +218,7 @@ void craftSelectComplete (string filename, selectCraftButton.interactable = true; reloadButton.interactable = enable; clearButton.interactable = enable; + UpdateCraftInfo (); } void craftSelectCancel () @@ -275,18 +305,71 @@ void UpdateFlag () } } + Sprite GetThumbnail() + { + string path = control.filename; + bool isStock = path.Substring(0, 6) == "Ships/"; + string craftType = control.craftType.ToString(); + string thumbName = Path.GetFileNameWithoutExtension(path); + string thumbPath; + if (isStock) { + thumbPath = $"Ships/@thumbs/{craftType}/{thumbName}.png"; + } else { + thumbPath = $"thumbs/{HighLogic.SaveFolder}_{craftType}_{thumbName}.png"; + } + var thumbTex = genericCraftThumb; + EL_Utils.LoadImage (ref thumbTex, thumbPath); + return MakeSprite(genericCraftThumb); + } + + void RebuildResourcList (List resources) + { + var resourceRect = resourceList.rectTransform; + int i = 0; + int childCount = resourceRect.childCount; + requiredResources.Clear (); + foreach (var res in resources) { + ELResourceDisplay display; + if (i < childCount) { + var child = resourceRect.GetChild(i); + display = child.GetComponent (); + } else { + display = resourceList.Add (); + display.Finish (); + } + requiredResources.Add (new ResourcePair (res, display)); + display.ResourceName = res.name; + display.RequiredAmount = res.amount; + + double available; + available = control.padResources.ResourceAmount (res.name); + display.AvailableAmount = available; + i++; + } + while (i < childCount) { + var go = resourceRect.GetChild (i++).gameObject; + Destroy (go); + } + } + void UpdateCraftInfo () { if (control != null) { bool enable = control.craftConfig != null; selectedCraft.gameObject.SetActive (enable); - - craftName.Text (control.craftName); - if (control.craftBoM != null || control.CreateBoM ()) { - craftBoM.Text(String.Join ("\n", control.craftBoM)); + craftView.gameObject.SetActive (enable); + + if (enable) { + craftName.Text (control.craftName); + RebuildResourcList (control.buildCost.required); + if (control.craftBoM != null || control.CreateBoM ()) { + craftBoM.Text(String.Join ("\n", control.craftBoM)); + } + craftThumb.image.sprite = GetThumbnail(); } } else { selectedCraft.gameObject.SetActive (false); + craftView.gameObject.SetActive (false); } } diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index a619fdb1..d2c415a6 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -36,5 +36,6 @@ public static class ELLocalization public static string Reload { get; } = "Reload"; public static string Clear { get; } = "Clear"; public static string Pad { get; } = "pad"; + public static string NotAvailable { get; } = "N/A"; } } diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs new file mode 100644 index 00000000..59258b0c --- /dev/null +++ b/Source/UI/ResourceDisplay.cs @@ -0,0 +1,182 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELResourceDisplay : LayoutAnchor + { + UIText resourceName; + UISlider fraction; + UIText required; + UIText available; + + public string ResourceName + { + get { return resourceName.tmpText.text; } + set { resourceName.tmpText.text = value; } + } + + string displayAmount (double amount) { + if (amount > 1000000) { + return Math.Round((amount / 1000000), 2).ToString() + " M"; + } else { + return Math.Round(amount, 2).ToString(); + } + } + + double requiredAmount; + public double RequiredAmount + { + get { return requiredAmount; } + set { + requiredAmount = value; + required.tmpText.text = displayAmount (value); + UpdateDsiplay (); + } + } + + double availableAmount; + public double AvailableAmount + { + get { return availableAmount; } + set { + availableAmount = value; + available.tmpText.text = displayAmount (value); + UpdateDsiplay (); + } + } + + void UpdateDsiplay() + { + double frac = 1; + Color color = UnityEngine.Color.green; + if (availableAmount >= 0 && availableAmount < requiredAmount) { + frac = availableAmount / requiredAmount; + color = UnityEngine.Color.yellow; + } else if (availableAmount < 0) { + color = UnityEngine.Color.white; + available.tmpText.text = ELLocalization.NotAvailable; + } + fraction.slider.SetValueWithoutNotify ((float) frac); + required.Color(color).Style(); + } + + public override void CreateUI() + { + base.CreateUI (); + + Vector2 nameMin = new Vector2 (0, 0); + Vector2 nameMax = new Vector2 (0.20f, 1); + Vector2 fractionMin = new Vector2 (0.225f, 0); + Vector2 fractionMax = new Vector2 (0.725f, 1); + Vector2 amountsMin = new Vector2 (0.75f, 0); + Vector2 amountsMax = new Vector2 (1, 1); + var requiredMin = new Vector2 (0, 0); + var requiredMax = new Vector2 (0.45f, 1); + var availableMin = new Vector2 (0.55f, 0); + var availableMax = new Vector2 (1, 1); + var textMargins = new Vector4 (5, 5, 10, 10); + + this + .DoPreferredHeight (true) + .DoMinHeight (true) + .FlexibleLayout (true, false) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Add () + .DoPreferredWidth (true) + .DoPreferredHeight (true) + .Anchor (nameMin, nameMax) + .SizeDelta (0, 0) + .Add ("AmountsPanel") + .Type (Image.Type.Sliced) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish() + .Add (out resourceName) + .Text("resource") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Left) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Add (out fraction, "ResourceFraction") + .Direction (Slider.Direction.LeftToRight) + .ShowHandle (false) + .Anchor (fractionMin, fractionMax) + .SizeDelta (0, 0) + .Finish () + .Add () + .Anchor (amountsMin, amountsMax) + .SizeDelta (0, 0) + .Add () + .DoPreferredWidth (true) + .DoPreferredHeight (true) + .Anchor (requiredMin, requiredMax) + .SizeDelta (0, 0) + .Add ("AmountsPanel") + .Type (Image.Type.Sliced) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish() + .Add (out required) + .Text ("500") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Right) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Add () + .DoPreferredWidth (true) + .DoPreferredHeight (true) + .Anchor (availableMin, availableMax) + .SizeDelta (0, 0) + .Add ("AmountsPanel") + .Type (Image.Type.Sliced) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () + .Add (out available) + .Text ("1000") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Right) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Finish () + .Finish (); + fraction.interactable = false; + fraction.slider.SetValueWithoutNotify(0.5f); + } + + public override void Style () + { + base.Style (); + } + } +} diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 3381c434..6c1cfca5 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License . */ using System; +using System.IO; using System.Text; using System.Reflection; using System.Collections; @@ -23,7 +24,6 @@ You should have received a copy of the GNU General Public License using System.Linq; using UnityEngine; -using KSP.IO; using Experience; namespace ExtraplanetaryLaunchpads { @@ -177,5 +177,20 @@ public static bool PrintIngredient (StringBuilder sb, Ingredient ingredient, str } return false; } + + static string applicationRoot; + public static bool LoadImage (ref Texture2D tex, string filename) + { + if (applicationRoot == null) { + applicationRoot = KSPUtil.ApplicationRootPath.Replace("\\", "/"); + } + bool ret = false; + string path = $"{applicationRoot}/{filename}"; + if (File.Exists (path)) { + ImageConversion.LoadImage (tex, File.ReadAllBytes (path)); + ret = true; + } + return ret; + } } } From 71723c0783362ae5b40e61e67b34055d6d5fb670 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 12:53:49 +0900 Subject: [PATCH 008/150] Remove excess path separator --- Source/lib/Utils.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 6c1cfca5..31b5fe69 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -185,7 +185,7 @@ public static bool LoadImage (ref Texture2D tex, string filename) applicationRoot = KSPUtil.ApplicationRootPath.Replace("\\", "/"); } bool ret = false; - string path = $"{applicationRoot}/{filename}"; + string path = $"{applicationRoot}{filename}"; if (File.Exists (path)) { ImageConversion.LoadImage (tex, File.ReadAllBytes (path)); ret = true; From 38404753f9ec843de4ea4ada1e00d66d9afc5bd9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 12:55:28 +0900 Subject: [PATCH 009/150] Fix stock craft thumbnail loading for stock I'd forgotten the craft filename was absolute, so the test wouldn't work. Instead, assume it's a player craft, try that path, then fall back to the stock path. If that fails, the green ship appears. --- Source/UI/CraftControl.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs index 52430e25..ae11668a 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftControl.cs @@ -308,17 +308,14 @@ void UpdateFlag () Sprite GetThumbnail() { string path = control.filename; - bool isStock = path.Substring(0, 6) == "Ships/"; string craftType = control.craftType.ToString(); string thumbName = Path.GetFileNameWithoutExtension(path); - string thumbPath; - if (isStock) { + string thumbPath = $"thumbs/{HighLogic.SaveFolder}_{craftType}_{thumbName}.png"; + var thumbTex = genericCraftThumb; + if (!EL_Utils.LoadImage (ref thumbTex, thumbPath)) { thumbPath = $"Ships/@thumbs/{craftType}/{thumbName}.png"; - } else { - thumbPath = $"thumbs/{HighLogic.SaveFolder}_{craftType}_{thumbName}.png"; + EL_Utils.LoadImage (ref thumbTex, thumbPath); } - var thumbTex = genericCraftThumb; - EL_Utils.LoadImage (ref thumbTex, thumbPath); return MakeSprite(genericCraftThumb); } From 8686d97e8f9f1909e979a395f77a641c54af2c47 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 12:59:07 +0900 Subject: [PATCH 010/150] Keep up to date :) --- KodeUI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KodeUI b/KodeUI index a2bc95c0..7064733e 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit a2bc95c0494a2089e6493b92f91541bb7761b9ca +Subproject commit 7064733e3062f5cc17a4da62f0956bd18157cf18 From a74678a5d026cb0606c5299cb085e5649f489a7b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 15:59:47 +0900 Subject: [PATCH 011/150] Check for padResource before building resource info Fixes NRE on scene load when the build window is open --- Source/UI/CraftControl.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs index ae11668a..f7c63dd8 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftControl.cs @@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License using System; using System.IO; using System.Reflection; +using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -349,6 +350,14 @@ void RebuildResourcList (List resources) } } + IEnumerator WaitAndRebuildResourcList (List resources) + { + while (control.padResources == null) { + yield return null; + } + RebuildResourcList (resources); + } + void UpdateCraftInfo () { if (control != null) { @@ -358,7 +367,7 @@ void UpdateCraftInfo () if (enable) { craftName.Text (control.craftName); - RebuildResourcList (control.buildCost.required); + StartCoroutine (WaitAndRebuildResourcList (control.buildCost.required)); if (control.craftBoM != null || control.CreateBoM ()) { craftBoM.Text(String.Join ("\n", control.craftBoM)); } From a919592e6887c43eb3d08131e622e2e602c35f83 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 16:02:37 +0900 Subject: [PATCH 012/150] Remove part fx when getting build cost Something in KSP 1.10 has changed such that particle effects remain (and active) when the vessel is destroyed the same frame as it was created. It may be that the effects were always there and they now are visible. However, with this, they are very much gone (verified using debug stuff). --- Source/BuildControl.cs | 30 ++++++++++++++++++++++++++++++ Source/Makefile | 2 ++ 2 files changed, 32 insertions(+) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index c7139f1d..46b2a764 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -1040,6 +1040,35 @@ void SanitizePart(Part part) { } } + void RemoveFX(Part part) + { + for (int i = part.fxGroups.Count; i-- > 0; ) { + var group = part.fxGroups[i]; + for (int j = group.fxEmittersNewSystem.Count; j-- > 0; ) { + var psys = group.fxEmittersNewSystem[j]; + if (psys && psys.gameObject) { + UnityEngine.Object.Destroy (psys.gameObject); + } + } + group.fxEmittersNewSystem.Clear(); + for (int j = group.lights.Count; j-- > 0; ) { + var light = group.lights[j]; + if (light && light.gameObject) { + UnityEngine.Object.Destroy (light.gameObject); + } + } + group.lights.Clear(); + if (group.sfx) { + UnityEngine.Object.Destroy (group.sfx); + group.sfx = null; + } + if (group.audio) { + UnityEngine.Object.Destroy (group.audio); + group.audio = null; + } + } + } + public CostReport getBuildCost (ConfigNode craft, string craftText = null) { lockedParts = false; @@ -1063,6 +1092,7 @@ public CostReport getBuildCost (ConfigNode craft, string craftText = null) craftVessel.Initialize (true); SetCraftOrbit (craftVessel, OrbitDriver.UpdateMode.IDLE); foreach (Part part in craftVessel.parts) { + RemoveFX(part); SanitizePart(part); part.ModulesOnStart(); } diff --git a/Source/Makefile b/Source/Makefile index cf68f1f3..9dfcbad1 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -146,6 +146,8 @@ UNITY := \ -r:UnityEngine.Physics2DModule.dll \ -r:UnityEngine.InputLegacyModule.dll \ -r:UnityEngine.ImageConversionModule.dll \ + -r:UnityEngine.ParticleSystemModule.dll \ + -r:UnityEngine.AudioModule.dll \ $e bin/Launchpad.dll: ${EL_FILES} ${KodeUI} From aa051dcb1ccdab249ae5b8c965aee85bff6e8cc9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 17:09:09 +0900 Subject: [PATCH 013/150] Tweak resource amount displays so 10k ranges fit 100k+ shifts to using 1M as a base. --- Source/UI/ResourceDisplay.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs index 59258b0c..aaf6d18a 100644 --- a/Source/UI/ResourceDisplay.cs +++ b/Source/UI/ResourceDisplay.cs @@ -39,8 +39,8 @@ public string ResourceName } string displayAmount (double amount) { - if (amount > 1000000) { - return Math.Round((amount / 1000000), 2).ToString() + " M"; + if (amount > 1e5) { + return Math.Round((amount / 1e6), 2).ToString() + " M"; } else { return Math.Round(amount, 2).ToString(); } @@ -88,14 +88,14 @@ public override void CreateUI() base.CreateUI (); Vector2 nameMin = new Vector2 (0, 0); - Vector2 nameMax = new Vector2 (0.20f, 1); - Vector2 fractionMin = new Vector2 (0.225f, 0); - Vector2 fractionMax = new Vector2 (0.725f, 1); - Vector2 amountsMin = new Vector2 (0.75f, 0); + Vector2 nameMax = new Vector2 (0.175f, 1); + Vector2 fractionMin = new Vector2 (0.20f, 0); + Vector2 fractionMax = new Vector2 (0.65f, 1); + Vector2 amountsMin = new Vector2 (0.675f, 0); Vector2 amountsMax = new Vector2 (1, 1); var requiredMin = new Vector2 (0, 0); - var requiredMax = new Vector2 (0.45f, 1); - var availableMin = new Vector2 (0.55f, 0); + var requiredMax = new Vector2 (0.475f, 1); + var availableMin = new Vector2 (0.525f, 0); var availableMax = new Vector2 (1, 1); var textMargins = new Vector4 (5, 5, 10, 10); @@ -144,6 +144,7 @@ public override void CreateUI() .Finish() .Add (out required) .Text ("500") + .Size (12) .Margin (textMargins) .Alignment (TextAlignmentOptions.Right) .Anchor (AnchorPresets.StretchAll) @@ -162,6 +163,7 @@ public override void CreateUI() .Finish () .Add (out available) .Text ("1000") + .Size (12) .Margin (textMargins) .Alignment (TextAlignmentOptions.Right) .Anchor (AnchorPresets.StretchAll) From 49cd103cd285a5b04ba8021754f9342c9c89bbcc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 17:35:21 +0900 Subject: [PATCH 014/150] Add the all important build button With this, the craft control panel is functionally complete. --- KodeUI | 2 +- Source/UI/CraftControl.cs | 21 ++++++++++++++++++++- Source/UI/Localization.cs | 1 + 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/KodeUI b/KodeUI index 7064733e..1ffabe72 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 7064733e3062f5cc17a4da62f0956bd18157cf18 +Subproject commit 1ffabe727c8320cd0886a4360fe9f6b7f8b19eb9 diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs index f7c63dd8..69111010 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftControl.cs @@ -41,6 +41,7 @@ public class ELCraftControl : Layout UIButton selectFlagButton; UIButton reloadButton; UIButton clearButton; + UIButton buildButton; struct ResourcePair { @@ -156,7 +157,14 @@ public override void CreateUI() .PreferredWidth (15) .Finish () .Finish () - .Finish (); + .Finish () + .Finish () + .Add (out buildButton) + .Text (ELLocalization.Build) + .OnClick (BuildCraft) + .FlexibleLayout (true, true) + .Finish() + .Finish(); craftView.VerticalScrollbar = scrollbar; craftView.Viewport.FlexibleLayout (true, true); @@ -208,6 +216,13 @@ public override void CreateUI() craftBoM.tmpText.linkedTextComponent = overflowText.tmpText; } + void BuildCraft () + { + if (control != null && control.builder.canBuild) { + control.BuildCraft (); + } + } + void craftSelectComplete (string filename, CBDLoadType lt) { control.craftType = craftList.craftType; @@ -219,6 +234,7 @@ void craftSelectComplete (string filename, CBDLoadType lt) selectCraftButton.interactable = true; reloadButton.interactable = enable; clearButton.interactable = enable; + buildButton.interactable = enable && control.builder.canBuild; UpdateCraftInfo (); } @@ -287,6 +303,7 @@ void Clear () control.UnloadCraft (); reloadButton.interactable = false; clearButton.interactable = false; + buildButton.interactable = false; } public override void Style () @@ -391,11 +408,13 @@ public void SetControl (ELBuildControl control) bool enable = control.craftConfig != null; reloadButton.interactable = enable; clearButton.interactable = enable; + buildButton.interactable = enable && control.builder.canBuild; } else { selectCraftButton.interactable = false; selectFlagButton.interactable = false; reloadButton.interactable = false; clearButton.interactable = false; + buildButton.interactable = false; } } } diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index d2c415a6..5e9c9ba2 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -37,5 +37,6 @@ public static class ELLocalization public static string Clear { get; } = "Clear"; public static string Pad { get; } = "pad"; public static string NotAvailable { get; } = "N/A"; + public static string Build { get; } = "Build"; } } From 26d9e507f11ef9b449f61c78238e09296ee8d22f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 20:26:56 +0900 Subject: [PATCH 015/150] Fire a custom game event for builder state change Intended for the new UI, but it could be useful for other purposes (eg, WBI might want to know when a build is done) --- Source/BuildControl.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index 46b2a764..f37a139f 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -29,6 +29,8 @@ namespace ExtraplanetaryLaunchpads { public class ELBuildControl : ELWorkSink { + public static readonly EventData onBuildStateChanged = new EventData ("onBuildStateChanged"); + public interface IBuilder { void Highlight (bool on); @@ -90,7 +92,14 @@ public RMResourceSet craftResources public bool craftBoMdirty { get; private set; } public CostReport buildCost { get; private set; } public CostReport builtStuff { get; private set; } - public State state { get; private set; } + State _state; + public State state { + get { return _state; } + private set { + _state = value; + onBuildStateChanged.Fire (this); + } + } public bool paused { get; private set; } public string KACalarmID = ""; @@ -889,11 +898,12 @@ public void Load (ConfigNode node) } if (node.HasValue ("state")) { var s = node.GetValue ("state"); - state = (State) Enum.Parse (typeof (State), s); - if (state == State.Dewarping) { + _state = (State) Enum.Parse (typeof (State), s); + if (_state == State.Dewarping) { // The game got saved while the Dewarping state was still // active. Rather than restarting the dewarp coroutine, // Just jump straight to the Complete state. + // DO want to fire the state for switch to Complete state = State.Complete; } } From 11369f262047799990c6de56a60bc4b53eec2797 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 20:32:56 +0900 Subject: [PATCH 016/150] Rename ResourceDisplay to ResourceLine I realized ResourceDisplay would be better for the set of resources being displayed rather than just the one. --- Source/Makefile | 2 +- Source/UI/CraftControl.cs | 10 +++++----- Source/UI/{ResourceDisplay.cs => ResourceLine.cs} | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename Source/UI/{ResourceDisplay.cs => ResourceLine.cs} (99%) diff --git a/Source/Makefile b/Source/Makefile index 9dfcbad1..ffb5e841 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -78,7 +78,7 @@ EL_FILES := \ UI/Localization.cs \ UI/MainWindow.cs \ UI/PadControl.cs \ - UI/ResourceDisplay.cs \ + UI/ResourceLine.cs \ UI/StatusBar.cs \ Workshop/ConstructionSkill.cs \ Workshop/ProtoWorkSink.cs \ diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftControl.cs index 69111010..6e5ca153 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftControl.cs @@ -46,8 +46,8 @@ public class ELCraftControl : Layout struct ResourcePair { public readonly BuildResource resource; - public readonly ELResourceDisplay display; - public ResourcePair (BuildResource resource, ELResourceDisplay display) + public readonly ELResourceLine display; + public ResourcePair (BuildResource resource, ELResourceLine display) { this.resource = resource; this.display = display; @@ -344,12 +344,12 @@ void RebuildResourcList (List resources) int childCount = resourceRect.childCount; requiredResources.Clear (); foreach (var res in resources) { - ELResourceDisplay display; + ELResourceLine display; if (i < childCount) { var child = resourceRect.GetChild(i); - display = child.GetComponent (); + display = child.GetComponent (); } else { - display = resourceList.Add (); + display = resourceList.Add (); display.Finish (); } requiredResources.Add (new ResourcePair (res, display)); diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceLine.cs similarity index 99% rename from Source/UI/ResourceDisplay.cs rename to Source/UI/ResourceLine.cs index aaf6d18a..d861cb86 100644 --- a/Source/UI/ResourceDisplay.cs +++ b/Source/UI/ResourceLine.cs @@ -25,7 +25,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELResourceDisplay : LayoutAnchor + public class ELResourceLine : LayoutAnchor { UIText resourceName; UISlider fraction; From 931c54d62df538e9152d39cbe0d8efecb71303e5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 20:47:34 +0900 Subject: [PATCH 017/150] Rename UI *Control to *View Fits in better with MVC :) (really, it eventually hit me that my problem with naming the build view was the "control" part). --- Source/Makefile | 4 ++-- Source/UI/{CraftControl.cs => CraftView.cs} | 2 +- Source/UI/MainWindow.cs | 12 ++++++------ Source/UI/{PadControl.cs => PadView.cs} | 18 +++++++++--------- 4 files changed, 18 insertions(+), 18 deletions(-) rename Source/UI/{CraftControl.cs => CraftView.cs} (99%) rename Source/UI/{PadControl.cs => PadView.cs} (93%) diff --git a/Source/Makefile b/Source/Makefile index ffb5e841..3d40551d 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -74,10 +74,10 @@ EL_FILES := \ Recycler/Recycler.cs \ Recycler/StateMachine.cs \ Target/Target.cs \ - UI/CraftControl.cs \ + UI/CraftView.cs \ UI/Localization.cs \ UI/MainWindow.cs \ - UI/PadControl.cs \ + UI/PadView.cs \ UI/ResourceLine.cs \ UI/StatusBar.cs \ Workshop/ConstructionSkill.cs \ diff --git a/Source/UI/CraftControl.cs b/Source/UI/CraftView.cs similarity index 99% rename from Source/UI/CraftControl.cs rename to Source/UI/CraftView.cs index 6e5ca153..70f8b5a7 100644 --- a/Source/UI/CraftControl.cs +++ b/Source/UI/CraftView.cs @@ -32,7 +32,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELCraftControl : Layout + public class ELCraftView : Layout { Sprite flagTexture; diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index 83a0f3d4..22d5f78e 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -31,8 +31,8 @@ namespace ExtraplanetaryLaunchpads { public class ELMainWindow : Window { ELStatusBar statusBar; - ELPadControl padControl; - ELCraftControl craftControl; + ELPadView padView; + ELCraftView craftView; public override void CreateUI() { @@ -48,12 +48,12 @@ public override void CreateUI() .Add(out statusBar, "StatusBar") .Finish() - .Add(out padControl, "PadControl") + .Add(out padView, "PadView") .Finish() - .Add(out craftControl, "CraftControl") + .Add(out craftView, "CraftView") .Finish() .Finish(); - padControl.craftControl = craftControl; + padView.craftView = craftView; } public override void Style () @@ -64,7 +64,7 @@ public override void Style () public void SetVessel (Vessel vessel) { statusBar.SetVessel (vessel); - padControl.SetVessel (vessel); + padView.SetVessel (vessel); } } } diff --git a/Source/UI/PadControl.cs b/Source/UI/PadView.cs similarity index 93% rename from Source/UI/PadControl.cs rename to Source/UI/PadView.cs index b10f8e0e..53c0f723 100644 --- a/Source/UI/PadControl.cs +++ b/Source/UI/PadView.cs @@ -31,7 +31,7 @@ namespace ExtraplanetaryLaunchpads { using OptionData = TMP_Dropdown.OptionData; - public class ELPadControl : LayoutAnchor + public class ELPadView : LayoutAnchor { Vessel vessel; ELVesselWorkNet worknet; @@ -41,8 +41,8 @@ public ELBuildControl control get { return _control; } private set { _control = value; - if (_craftControl != null) { - _craftControl.SetControl (_control); + if (_craftView != null) { + _craftView.SetControl (_control); } } } @@ -53,14 +53,14 @@ private set { UIDropdown padSelector; UIToggle highlightPad; - ELCraftControl _craftControl; - public ELCraftControl craftControl + ELCraftView _craftView; + public ELCraftView craftView { - get { return _craftControl; } + get { return _craftView; } set { - _craftControl = value; - if (_craftControl != null) { - _craftControl.SetControl (control); + _craftView = value; + if (_craftView != null) { + _craftView.SetControl (control); } } } From 522de12692f28ee6ac0670a8af46e87b9a3cf4fa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 20:55:54 +0900 Subject: [PATCH 018/150] Start work on the build view Most importantly, the display switches from the craft view to the build view when the build button is pressed. --- Source/Makefile | 1 + Source/UI/BuildView.cs | 215 ++++++++++++++++++++++++++++++++++++++ Source/UI/CraftView.cs | 10 +- Source/UI/Localization.cs | 7 ++ Source/UI/MainWindow.cs | 9 +- Source/UI/PadView.cs | 37 +++++-- 6 files changed, 263 insertions(+), 16 deletions(-) create mode 100644 Source/UI/BuildView.cs diff --git a/Source/Makefile b/Source/Makefile index 3d40551d..36a1150b 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -74,6 +74,7 @@ EL_FILES := \ Recycler/Recycler.cs \ Recycler/StateMachine.cs \ Target/Target.cs \ + UI/BuildView.cs \ UI/CraftView.cs \ UI/Localization.cs \ UI/MainWindow.cs \ diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs new file mode 100644 index 00000000..59d15c69 --- /dev/null +++ b/Source/UI/BuildView.cs @@ -0,0 +1,215 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ELBuildView : Layout + { + UIButton pauseButton; + UIButton finalizeButton; + UIButton cancelButton; + + struct ResourcePair + { + public readonly BuildResource resource; + public readonly ELResourceLine display; + public ResourcePair (BuildResource resource, ELResourceLine display) + { + this.resource = resource; + this.display = display; + } + } + + ScrollView craftView; + Layout selectedCraft; + Layout resourceList; + //List requiredResources; + UIText craftName; + + ELBuildControl control; + + public override void CreateUI() + { + base.CreateUI (); + + UIScrollbar scrollbar; + Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add() + .Background("KodeUI/Default/background") + .BackgroundColor(UnityEngine.Color.white) + .Vertical() + .Padding(8) + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .Anchor(AnchorPresets.HorStretchTop) + .FlexibleLayout(true,true) + .PreferredHeight(300) + .Add (out selectedCraft) + .Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .FlexibleLayout(true,false) + .Add () + .Text (ELLocalization.SelectedCraft) + .Finish () + .Add() + .MinSize(15,-1) + .Finish() + .Add (out craftName) + .Finish () + .Finish () + .Add (out craftView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Add (out scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Add (out pauseButton) + .Text (PauseResumeText ()) + .OnClick (PauseResume) + .FlexibleLayout (true, true) + .Finish() + .Add (out finalizeButton) + .Text (ELLocalization.FinalizeBuild) + .OnClick (FinalizeBuild) + .FlexibleLayout (true, true) + .Finish() + .Add (out cancelButton) + .Text (CancelRestartText ()) + .OnClick (CancelRestart) + .FlexibleLayout (true, true) + .Finish() + .Finish() + .Finish(); + + craftView.VerticalScrollbar = scrollbar; + craftView.Viewport.FlexibleLayout (true, true); + craftView.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .WidthDelta(0) + .Add (out resourceList) + .Vertical() + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () + .Finish (); + } + + string PauseResumeText () + { + if (control == null) { + return ELLocalization.PauseBuild; + } + if (control.state == ELBuildControl.State.Building) { + if (control.paused) { + return ELLocalization.ResumeBuild; + } else { + return ELLocalization.PauseBuild; + } + } else { + if (control.paused) { + return ELLocalization.ResumeTeardown; + } else { + return ELLocalization.PauseTeardown; + } + } + } + + void FinalizeBuild () + { + control.BuildAndLaunchCraft (); + } + + void PauseResume () + { + if (control.paused) { + control.ResumeBuild (); + } else { + control.PauseBuild (); + } + } + + void CancelRestart () + { + if (control.paused) { + control.CancelBuild (); + } else { + control.UnCancelBuild (); + } + } + + string CancelRestartText () + { + if (control == null) { + return ELLocalization.CancelBuild; + } + if (control.state == ELBuildControl.State.Building) { + return ELLocalization.CancelBuild; + } else { + return ELLocalization.RestartBuild; + } + } + + public void UpdateControl (ELBuildControl control) + { + this.control = control; + if (control != null + && (control.state == ELBuildControl.State.Building + || control.state == ELBuildControl.State.Canceling)) { + gameObject.SetActive (true); + } else { + gameObject.SetActive (false); + } + } + } +} diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index 70f8b5a7..aaaf904c 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -157,7 +157,6 @@ public override void CreateUI() .PreferredWidth (15) .Finish () .Finish () - .Finish () .Finish () .Add (out buildButton) .Text (ELLocalization.Build) @@ -396,11 +395,13 @@ void UpdateCraftInfo () } } - public void SetControl (ELBuildControl control) + public void UpdateControl (ELBuildControl control) { this.control = control; - - if (control != null) { + if (control != null + && (control.state == ELBuildControl.State.Idle + || control.state == ELBuildControl.State.Planning)) { + gameObject.SetActive (true); UpdateFlag (); UpdateCraftInfo (); selectCraftButton.interactable = true; @@ -410,6 +411,7 @@ public void SetControl (ELBuildControl control) clearButton.interactable = enable; buildButton.interactable = enable && control.builder.canBuild; } else { + gameObject.SetActive (false); selectCraftButton.interactable = false; selectFlagButton.interactable = false; reloadButton.interactable = false; diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 5e9c9ba2..0af481d1 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -38,5 +38,12 @@ public static class ELLocalization public static string Pad { get; } = "pad"; public static string NotAvailable { get; } = "N/A"; public static string Build { get; } = "Build"; + public static string PauseBuild { get; } = "Pause Build"; + public static string ResumeBuild { get; } = "Resume Build"; + public static string PauseTeardown { get; } = "Pause Teardown"; + public static string ResumeTeardown { get; } = "Resume Teardown"; + public static string FinalizeBuild { get; } = "Finalize Build"; + public static string CancelBuild { get; } = "Cancel Build"; + public static string RestartBuild { get; } = "Restart Build"; } } diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index 22d5f78e..fbdfa2ad 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -33,6 +33,7 @@ public class ELMainWindow : Window ELStatusBar statusBar; ELPadView padView; ELCraftView craftView; + ELBuildView buildView; public override void CreateUI() { @@ -52,8 +53,14 @@ public override void CreateUI() .Finish() .Add(out craftView, "CraftView") .Finish() + .Add(out buildView, "BuildView") + .Finish() .Finish(); - padView.craftView = craftView; + + craftView.gameObject.SetActive (false); + buildView.gameObject.SetActive (false); + padView.AddListener (craftView.UpdateControl); + padView.AddListener (buildView.UpdateControl); } public override void Style () diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 53c0f723..b346c322 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -20,6 +20,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Linq; using UnityEngine; +using UnityEngine.Events; using TMPro; using KodeUI; @@ -33,17 +34,26 @@ namespace ExtraplanetaryLaunchpads { public class ELPadView : LayoutAnchor { + public class PadEvent : UnityEvent {} + PadEvent padEvent = new PadEvent (); + + public void AddListener (UnityAction action) + { + padEvent.AddListener (action); + action.Invoke (control); + } + + Vessel vessel; ELVesselWorkNet worknet; ELBuildControl _control; + public ELBuildControl control { get { return _control; } private set { _control = value; - if (_craftView != null) { - _craftView.SetControl (_control); - } + padEvent.Invoke (_control); } } @@ -53,15 +63,20 @@ private set { UIDropdown padSelector; UIToggle highlightPad; - ELCraftView _craftView; - public ELCraftView craftView + protected override void Awake () { - get { return _craftView; } - set { - _craftView = value; - if (_craftView != null) { - _craftView.SetControl (control); - } + ELBuildControl.onBuildStateChanged.Add (onBuildStateChanged); + } + + protected override void OnDestroy () + { + ELBuildControl.onBuildStateChanged.Remove (onBuildStateChanged); + } + + void onBuildStateChanged (ELBuildControl control) + { + if (control == this.control) { + padEvent.Invoke (control); } } From b8bc76a249ced312375f18ba795b895507243bc0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 2 Oct 2020 22:11:01 +0900 Subject: [PATCH 019/150] Correct the github issues url My github id hasn't been taniwha-qf for years. --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 9187856f..8cba5fe5 100644 --- a/README.txt +++ b/README.txt @@ -65,7 +65,7 @@ Mods considered essential for getting the most out of EL: http://forum.kerbalspaceprogram.com/threads/37707 Please report all issues at -https://github.com/taniwha-qf/Extraplanetary-Launchpads/issues +https://github.com/taniwha/Extraplanetary-Launchpads/issues Many resource containers use HexCans by Greys (https://github.com/Greys0/HexCans). From 5ba94a2e1beeff8f6f014835aac1616ab2490f30 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 14:17:31 +0900 Subject: [PATCH 020/150] Check padResources before showing required resources Even though this GUI code will go away soon, the NRE hides other issues. --- Source/GUI/BuildWindow.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs index cfa8a96e..cf6ba138 100644 --- a/Source/GUI/BuildWindow.cs +++ b/Source/GUI/BuildWindow.cs @@ -571,6 +571,9 @@ void ResourceHeader (string header) void RequiredResources () { + if (control.padResources == null) { + return; + } ResourceHeader ("Resources required to build:"); foreach (var br in control.buildCost.required) { double a = br.amount; From 82f302a5d399902356e1ade515759120f272a232 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 14:18:36 +0900 Subject: [PATCH 021/150] Start making RMResourceInfo more encapsulated I should have done this in the first place. --- Source/ResourceManager/ResourceInfo.cs | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Source/ResourceManager/ResourceInfo.cs b/Source/ResourceManager/ResourceInfo.cs index e96ac253..9173cc33 100644 --- a/Source/ResourceManager/ResourceInfo.cs +++ b/Source/ResourceManager/ResourceInfo.cs @@ -26,5 +26,51 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { public class RMResourceInfo { public List containers = new List(); + + public bool flowState + { + get { + for (int i = containers.Count; i-- > 0; ) { + if (containers[i].flowState) { + return true; + } + } + return false; + } + set { + for (int i = containers.Count; i-- > 0; ) { + containers[i].flowState = value; + } + } + } + + public double amount + { + get { + double amount = 0; + for (int i = containers.Count; i-- > 0; ) { + amount += containers[i].amount; + } + return amount; + } + } + + public double maxAmount + { + get { + double maxAmount = 0; + for (int i = containers.Count; i-- > 0; ) { + maxAmount += containers[i].maxAmount; + } + return maxAmount; + } + } + + public void RemoveAllResources () + { + for (int i = containers.Count; i-- > 0; ) { + containers[i].amount = 0.0; + } + } } } From 26f5f3220ed4cc51cce356680bb165152de1a211 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 14:19:28 +0900 Subject: [PATCH 022/150] Make RMResourceSet string-indexible --- Source/ResourceManager/ResourceSet.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/ResourceManager/ResourceSet.cs b/Source/ResourceManager/ResourceSet.cs index c2ba76b8..a982c107 100644 --- a/Source/ResourceManager/ResourceSet.cs +++ b/Source/ResourceManager/ResourceSet.cs @@ -34,6 +34,15 @@ public class RMResourceSet { public bool balanced; public string name; + public RMResourceInfo this[string res] + { + get { + RMResourceInfo info; + resources.TryGetValue (res, out info); + return info; + } + } + public bool GetFlowState (string res) { if (resources.ContainsKey (res)) { From 8acdcfb6f5ff47d5b8e6612c97dc52009ccd5127 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 14:20:30 +0900 Subject: [PATCH 023/150] Clean up some resource set code It now uses the new properties on RMResourceInfo for some things. More work to be done. --- Source/ResourceManager/ResourceSet.cs | 29 +++++---------------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/Source/ResourceManager/ResourceSet.cs b/Source/ResourceManager/ResourceSet.cs index a982c107..235ba048 100644 --- a/Source/ResourceManager/ResourceSet.cs +++ b/Source/ResourceManager/ResourceSet.cs @@ -46,12 +46,7 @@ public RMResourceInfo this[string res] public bool GetFlowState (string res) { if (resources.ContainsKey (res)) { - RMResourceInfo info = resources[res]; - for (int i = info.containers.Count; i-- > 0; ) { - if (info.containers[i].flowState) { - return true; - } - } + return resources[res].flowState; } return false; } @@ -59,10 +54,7 @@ public bool GetFlowState (string res) public void SetFlowState (string res, bool state) { if (resources.ContainsKey (res)) { - RMResourceInfo info = resources[res]; - for (int i = info.containers.Count; i-- > 0; ) { - info.containers[i].flowState = state; - } + resources[res].flowState = state; } } @@ -178,10 +170,7 @@ public void RemoveAllResources (HashSet resources_to_remove = null) if (resources_to_remove != null && !resources_to_remove.Contains (resource)) { continue; } - RMResourceInfo resourceInfo = pair.Value; - foreach (var container in resourceInfo.containers) { - container.amount = 0.0; - } + pair.Value.RemoveAllResources (); } } @@ -192,11 +181,7 @@ public double ResourceCapacity (string resource) if (!resources.ContainsKey (resource)) return 0.0; RMResourceInfo resourceInfo = resources[resource]; - double capacity = 0.0; - foreach (var container in resourceInfo.containers) { - capacity += container.maxAmount; - } - return capacity; + return resourceInfo.maxAmount; } // Return the vessel's total available amount of the resource. @@ -206,11 +191,7 @@ public double ResourceAmount (string resource) if (!resources.ContainsKey (resource)) return 0.0; RMResourceInfo resourceInfo = resources[resource]; - double amount = 0.0; - foreach (var container in resourceInfo.containers) { - amount += container.amount; - } - return amount; + return resourceInfo.amount; } // Transfer a resource into (positive amount) or out of (negative From 569908abc0ffe21b64862141f4b13d7b425875e7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 14:25:25 +0900 Subject: [PATCH 024/150] Make a generic resource display Not yet sure if it will be good for the resource manager, but it is definitely capable of handling required resources and build progress (or will be when BuildView is done). --- Source/Makefile | 2 + Source/UI/BuildView.cs | 62 ++++++++++++++++---- Source/UI/CraftView.cs | 107 ++++++++++++++++------------------- Source/UI/IResourceLine.cs | 36 ++++++++++++ Source/UI/Localization.cs | 1 + Source/UI/ResourceDisplay.cs | 104 ++++++++++++++++++++++++++++++++++ Source/UI/ResourceLine.cs | 82 +++++++++++++++------------ 7 files changed, 289 insertions(+), 105 deletions(-) create mode 100644 Source/UI/IResourceLine.cs create mode 100644 Source/UI/ResourceDisplay.cs diff --git a/Source/Makefile b/Source/Makefile index 36a1150b..6fcb4dd3 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -76,9 +76,11 @@ EL_FILES := \ Target/Target.cs \ UI/BuildView.cs \ UI/CraftView.cs \ + UI/IResourceLine.cs \ UI/Localization.cs \ UI/MainWindow.cs \ UI/PadView.cs \ + UI/ResourceDisplay.cs \ UI/ResourceLine.cs \ UI/StatusBar.cs \ Workshop/ConstructionSkill.cs \ diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index 59d15c69..54788d66 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -34,25 +34,53 @@ namespace ExtraplanetaryLaunchpads { public class ELBuildView : Layout { - UIButton pauseButton; - UIButton finalizeButton; - UIButton cancelButton; - - struct ResourcePair + public class ProgressResource : ELResourceDisplay.BaseResourceLine { - public readonly BuildResource resource; - public readonly ELResourceLine display; - public ResourcePair (BuildResource resource, ELResourceLine display) + ELBuildControl control; + BuildResource requiredResource; + + public override string ResourceInfo + { + get { + if (control.paused) { + return ELLocalization.Paused; + } + double fraction = ResourceFraction; + string percent = (fraction * 100).ToString ("G4") + "%"; + return percent; + } + } + public override double ResourceFraction + { + get { + double required = requiredResource.amount; + double built = RequiredAmount; + + if (required < 0) { + return 0; + } else if (built < required) { + return (required - built) / required; + } else { + return 1; + } + } + } + + public ProgressResource (BuildResource built, BuildResource required, RMResourceInfo pad, ELBuildControl control) + : base (built, pad) { - this.resource = resource; - this.display = display; + this.control = control; + requiredResource = required; } } + UIButton pauseButton; + UIButton finalizeButton; + UIButton cancelButton; + ScrollView craftView; Layout selectedCraft; Layout resourceList; - //List requiredResources; UIText craftName; ELBuildControl control; @@ -211,5 +239,17 @@ public void UpdateControl (ELBuildControl control) gameObject.SetActive (false); } } + + void RebuildResources () + { + } + + IEnumerator WaitAndRebuildResources () + { + while (control.padResources == null) { + yield return null; + } + RebuildResources (); + } } } diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index aaaf904c..30979161 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -34,6 +34,28 @@ namespace ExtraplanetaryLaunchpads { public class ELCraftView : Layout { + class RequiredResource : ELResourceDisplay.BaseResourceLine + { + public override string ResourceInfo { get { return null; } } + public override double ResourceFraction + { + get { + double required = RequiredAmount; + double available = AvailableAmount; + + if (available < 0) { + return 0; + } else if (available < required) { + return available / required; + } + return 1; + } + } + + public RequiredResource (BuildResource build, RMResourceInfo pad) + : base (build, pad) + { } + } Sprite flagTexture; @@ -43,21 +65,9 @@ public class ELCraftView : Layout UIButton clearButton; UIButton buildButton; - struct ResourcePair - { - public readonly BuildResource resource; - public readonly ELResourceLine display; - public ResourcePair (BuildResource resource, ELResourceLine display) - { - this.resource = resource; - this.display = display; - } - } - ScrollView craftView; Layout selectedCraft; - Layout resourceList; - List requiredResources; + ELResourceDisplay resourceList; UIText craftName; UIText craftBoM; UIImage craftThumb; @@ -67,6 +77,8 @@ public ResourcePair (BuildResource resource, ELResourceLine display) FlagBrowser flagBrowser; ELCraftBrowser craftList; + List requiredResources; + static Texture2D genericCraftThumb; static FlagBrowser _flagBrowserPrefab; @@ -86,7 +98,9 @@ public override void CreateUI() if (!genericCraftThumb) { genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); } - requiredResources = new List (); + if (requiredResources == null) { + requiredResources = new List (); + } base.CreateUI (); @@ -174,12 +188,7 @@ public override void CreateUI() .Anchor (AnchorPresets.HorStretchTop) .PreferredSizeFitter(true, false) .WidthDelta(0) - .Add (out resourceList) - .Vertical() - .ControlChildSize (true, true) - .ChildForceExpand (false, false) - .FlexibleLayout (true, false) - .SizeDelta (0, 0) + .Add (out resourceList) .Finish () .Add () .Horizontal () @@ -336,44 +345,6 @@ Sprite GetThumbnail() return MakeSprite(genericCraftThumb); } - void RebuildResourcList (List resources) - { - var resourceRect = resourceList.rectTransform; - int i = 0; - int childCount = resourceRect.childCount; - requiredResources.Clear (); - foreach (var res in resources) { - ELResourceLine display; - if (i < childCount) { - var child = resourceRect.GetChild(i); - display = child.GetComponent (); - } else { - display = resourceList.Add (); - display.Finish (); - } - requiredResources.Add (new ResourcePair (res, display)); - display.ResourceName = res.name; - display.RequiredAmount = res.amount; - - double available; - available = control.padResources.ResourceAmount (res.name); - display.AvailableAmount = available; - i++; - } - while (i < childCount) { - var go = resourceRect.GetChild (i++).gameObject; - Destroy (go); - } - } - - IEnumerator WaitAndRebuildResourcList (List resources) - { - while (control.padResources == null) { - yield return null; - } - RebuildResourcList (resources); - } - void UpdateCraftInfo () { if (control != null) { @@ -383,7 +354,7 @@ void UpdateCraftInfo () if (enable) { craftName.Text (control.craftName); - StartCoroutine (WaitAndRebuildResourcList (control.buildCost.required)); + StartCoroutine (WaitAndRebuildResources ()); if (control.craftBoM != null || control.CreateBoM ()) { craftBoM.Text(String.Join ("\n", control.craftBoM)); } @@ -419,5 +390,23 @@ public void UpdateControl (ELBuildControl control) buildButton.interactable = false; } } + + void RebuildResources () + { + requiredResources.Clear (); + foreach (var res in control.buildCost.required) { + var available = control.padResources[res.name]; + requiredResources.Add (new RequiredResource (res, available)); + } + resourceList.Resources (requiredResources); + } + + IEnumerator WaitAndRebuildResources () + { + while (control.padResources == null) { + yield return null; + } + RebuildResources (); + } } } diff --git a/Source/UI/IResourceLine.cs b/Source/UI/IResourceLine.cs new file mode 100644 index 00000000..ef2b2467 --- /dev/null +++ b/Source/UI/IResourceLine.cs @@ -0,0 +1,36 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public interface IResourceLine + { + string ResourceName { get; } + string ResourceInfo { get; } + double ResourceFraction { get; } + double RequiredAmount { get; } + double AvailableAmount { get; } + } +} diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 0af481d1..83e7c4b6 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -45,5 +45,6 @@ public static class ELLocalization public static string FinalizeBuild { get; } = "Finalize Build"; public static string CancelBuild { get; } = "Cancel Build"; public static string RestartBuild { get; } = "Restart Build"; + public static string Paused { get; } = "[paused]"; } } diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs new file mode 100644 index 00000000..05522323 --- /dev/null +++ b/Source/UI/ResourceDisplay.cs @@ -0,0 +1,104 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELResourceDisplay : Layout + { + public abstract class BaseResourceLine : IResourceLine + { + protected string name; + protected BuildResource buildResource; + protected RMResourceInfo padResource; + + public virtual string ResourceName { get { return name; } } + public abstract string ResourceInfo { get; } + public abstract double ResourceFraction { get; } + public virtual double RequiredAmount { + get { return buildResource.amount; } + } + public virtual double AvailableAmount { + get { return padResource != null ? padResource.amount : 0; } + } + + public BaseResourceLine (BuildResource build, RMResourceInfo pad) + { + name = build.name; + buildResource = build; + padResource = pad; + } + } + + List resources; + + public override void CreateUI() + { + this.Horizontal () + .ChildForceExpand(false,false) + .FlexibleLayout (true, false) + .SizeDelta (0, 0); + } + + void RebuildContent () + { + var contentRect = rectTransform; + int childCount = contentRect.childCount; + int childIndex = 0; + int itemIndex = 0; + int itemCount = resources.Count; + + while (childIndex < childCount && itemIndex < itemCount) { + var child = contentRect.GetChild (childIndex); + var item = child.GetComponent (); + item.Resource (resources[itemIndex]); + ++childIndex; + ++itemIndex; + } + while (childIndex < childCount) { + var go = contentRect.GetChild (childIndex++).gameObject; + Destroy (go); + } + while (itemIndex < itemCount) { + this.Add () + .Resource (resources[itemIndex]) + .FlexibleLayout(true, false) + .SizeDelta (0, 0) + .Finish(); + ++itemIndex; + } + } + + public ELResourceDisplay Resources (List resources) + { + this.resources = resources; + RebuildContent (); + return this; + } + } +} diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index d861cb86..8e647b7b 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -29,14 +29,11 @@ public class ELResourceLine : LayoutAnchor { UIText resourceName; UISlider fraction; + UIText info; UIText required; UIText available; - public string ResourceName - { - get { return resourceName.tmpText.text; } - set { resourceName.tmpText.text = value; } - } + IResourceLine resource; string displayAmount (double amount) { if (amount > 1e5) { @@ -46,41 +43,28 @@ string displayAmount (double amount) { } } - double requiredAmount; - public double RequiredAmount + public void UpdateDisplay() { - get { return requiredAmount; } - set { - requiredAmount = value; - required.tmpText.text = displayAmount (value); - UpdateDsiplay (); + if (resource.ResourceInfo != null) { + info.Text(resource.ResourceInfo); } - } + double frac = resource.ResourceFraction; + fraction.slider.SetValueWithoutNotify ((float) frac); - double availableAmount; - public double AvailableAmount - { - get { return availableAmount; } - set { - availableAmount = value; - available.tmpText.text = displayAmount (value); - UpdateDsiplay (); - } - } + double required = resource.RequiredAmount; + double available = resource.AvailableAmount; - void UpdateDsiplay() - { - double frac = 1; + if (available >= 0) { + this.available.Text (displayAmount (available)); + } Color color = UnityEngine.Color.green; - if (availableAmount >= 0 && availableAmount < requiredAmount) { - frac = availableAmount / requiredAmount; + if (available >= 0 && available < required) { color = UnityEngine.Color.yellow; - } else if (availableAmount < 0) { + } else if (available < 0) { color = UnityEngine.Color.white; - available.tmpText.text = ELLocalization.NotAvailable; } - fraction.slider.SetValueWithoutNotify ((float) frac); - required.Color(color).Style(); + this.required.Color(color).Style(); + this.required.Text (displayAmount (required)); } public override void CreateUI() @@ -123,11 +107,21 @@ public override void CreateUI() .SizeDelta (0, 0) .Finish () .Finish () - .Add (out fraction, "ResourceFraction") - .Direction (Slider.Direction.LeftToRight) - .ShowHandle (false) + .Add () .Anchor (fractionMin, fractionMax) .SizeDelta (0, 0) + .Add (out fraction, "ResourceFraction") + .Direction (Slider.Direction.LeftToRight) + .ShowHandle (false) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () + .Add (out info, "ResourceInfo") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Center) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Finish () .Finish () .Add () .Anchor (amountsMin, amountsMax) @@ -180,5 +174,23 @@ public override void Style () { base.Style (); } + + public ELResourceLine Resource (IResourceLine resource) + { + this.resource = resource; + resourceName.Text (resource.ResourceName); + required.Text (displayAmount (resource.RequiredAmount)); + if (resource.AvailableAmount >= 0) { + available.Text (displayAmount (resource.AvailableAmount)); + } else { + available.Text (ELLocalization.NotAvailable); + } + return this; + } + + void Update () + { + UpdateDisplay (); + } } } From 0aabf80ec85d6ec98d06ce6d8f3f99e098e35f32 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 18:03:11 +0900 Subject: [PATCH 025/150] Implement progress update in the build view A few minor issues, but it works nicely (at least for one resource). --- Source/UI/BuildView.cs | 57 +++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index 54788d66..f0fb9b48 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -47,6 +47,10 @@ public override string ResourceInfo } double fraction = ResourceFraction; string percent = (fraction * 100).ToString ("G4") + "%"; + double eta = CalculateETA (); + if (eta > 0) { + percent += " " + EL_Utils.TimeSpanString (eta); + } return percent; } } @@ -58,10 +62,13 @@ public override double ResourceFraction if (required < 0) { return 0; - } else if (built < required) { + } + if (built < 0) { + return 1; + } else if (built <= required) { return (required - built) / required; } else { - return 1; + return 0; } } } @@ -72,6 +79,22 @@ public ProgressResource (BuildResource built, BuildResource required, RMResource this.control = control; requiredResource = required; } + + public double CalculateETA () + { + double frames; + if (buildResource.deltaAmount <= 0) { + return 0; + } + if (control.state == ELBuildControl.State.Building) { + frames = buildResource.amount / buildResource.deltaAmount; + } else { + double remaining = buildResource.amount; + remaining -= requiredResource.amount; + frames = remaining / buildResource.deltaAmount; + } + return frames * TimeWarp.fixedDeltaTime; + } } UIButton pauseButton; @@ -80,13 +103,19 @@ public ProgressResource (BuildResource built, BuildResource required, RMResource ScrollView craftView; Layout selectedCraft; - Layout resourceList; + ELResourceDisplay resourceList; UIText craftName; + List progressResources; + ELBuildControl control; public override void CreateUI() { + if (progressResources == null) { + progressResources = new List (); + } + base.CreateUI (); UIScrollbar scrollbar; @@ -163,12 +192,7 @@ public override void CreateUI() .Anchor (AnchorPresets.HorStretchTop) .PreferredSizeFitter(true, false) .WidthDelta(0) - .Add (out resourceList) - .Vertical() - .ControlChildSize (true, true) - .ChildForceExpand (false, false) - .FlexibleLayout (true, false) - .SizeDelta (0, 0) + .Add (out resourceList) .Finish () .Finish (); } @@ -235,13 +259,28 @@ public void UpdateControl (ELBuildControl control) && (control.state == ELBuildControl.State.Building || control.state == ELBuildControl.State.Canceling)) { gameObject.SetActive (true); + craftName.Text (control.craftName); + StartCoroutine (WaitAndRebuildResources ()); } else { gameObject.SetActive (false); } } + static BuildResource FindResource (List reslist, string name) + { + return reslist.Where(r => r.name == name).FirstOrDefault (); + } + void RebuildResources () { + progressResources.Clear (); + foreach (var res in control.builtStuff.required) { + var req = FindResource (control.buildCost.required, res.name); + var available = control.padResources[res.name]; + var line = new ProgressResource (res, req, available, control); + progressResources.Add (line); + } + resourceList.Resources (progressResources); } IEnumerator WaitAndRebuildResources () From 61fc2d7aebcea5708079c44ad026889d876c6243 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 19:08:11 +0900 Subject: [PATCH 026/150] Fire and event when building is paused or unpaused --- Source/BuildControl.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index f37a139f..c213f9fc 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -166,13 +166,19 @@ public void UnCancelBuild () public void PauseBuild () { if (state == State.Building || state == State.Canceling) { - paused = true; + if (!paused) { + paused = true; + onBuildStateChanged.Fire (this); + } } } public void ResumeBuild () { - paused = false; + if (paused) { + paused = false; + onBuildStateChanged.Fire (this); + } } public bool isActive From b5a312854aea7498c30be244509081f4d1aa7d4a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 19:08:50 +0900 Subject: [PATCH 027/150] Fix up build view's button issues Mostly: there are some problems with the auto-layout, but that's a problem in KodeUI. --- Source/UI/BuildView.cs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index f0fb9b48..571fbbc2 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -233,7 +233,7 @@ void PauseResume () void CancelRestart () { - if (control.paused) { + if (control.state == ELBuildControl.State.Building) { control.CancelBuild (); } else { control.UnCancelBuild (); @@ -255,12 +255,30 @@ string CancelRestartText () public void UpdateControl (ELBuildControl control) { this.control = control; - if (control != null - && (control.state == ELBuildControl.State.Building - || control.state == ELBuildControl.State.Canceling)) { - gameObject.SetActive (true); - craftName.Text (control.craftName); - StartCoroutine (WaitAndRebuildResources ()); + if (control != null) { + bool enable = false; + bool complete = false; + + switch (control.state) { + case ELBuildControl.State.Building: + case ELBuildControl.State.Canceling: + enable = true; + complete = false; + break; + case ELBuildControl.State.Complete: + enable = true; + complete = true;; + break; + } + gameObject.SetActive (enable); + if (enable) { + pauseButton.Text (PauseResumeText ()); + cancelButton.Text (CancelRestartText ()); + pauseButton.gameObject.SetActive (!complete); + finalizeButton.gameObject.SetActive (complete); + craftName.Text (control.craftName); + StartCoroutine (WaitAndRebuildResources ()); + } } else { gameObject.SetActive (false); } From 1d3feeda125ad2380a0e4c029ee370758fb24414 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 19:29:06 +0900 Subject: [PATCH 028/150] Fix clingy main window Gotta destroy the game object, not the component. --- Source/GUI/BuildWindow.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs index cf6ba138..afb82e79 100644 --- a/Source/GUI/BuildWindow.cs +++ b/Source/GUI/BuildWindow.cs @@ -328,7 +328,8 @@ void OnDestroy () GameEvents.onShowUI.Remove (onShowUI); GameEvents.onVesselSwitchingToUnloaded.Remove (VMSaveHack); if (mainWindow) { - Destroy (mainWindow); + Destroy (mainWindow.gameObject); + mainWindow = null; } } From 4ec420633bdf8bf20e478de6f8f33d4a13a0c495 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 21:04:31 +0900 Subject: [PATCH 029/150] Ensure the flag icon is always 8:5 might need an inner container for it, though, as it over-fills the button. --- Source/UI/BuildView.cs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index 571fbbc2..457c507a 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -118,6 +118,11 @@ public override void CreateUI() base.CreateUI (); + var leftMin = new Vector2 (0, 0); + var leftMax = new Vector2 (0.5f, 1); + var rightMin = new Vector2 (0.5f, 0); + var rightMax = new Vector2 (1, 1); + UIScrollbar scrollbar; Vertical () .ControlChildSize(true, true) @@ -159,26 +164,28 @@ public override void CreateUI() .Finish () .Finish () .Finish () - .Add () - .Horizontal () - .ControlChildSize (true, true) - .ChildForceExpand (false, false) + .Add () + .DoPreferredHeight (true) .FlexibleLayout (true, false) .SizeDelta (0, 0) .Add (out pauseButton) .Text (PauseResumeText ()) .OnClick (PauseResume) - .FlexibleLayout (true, true) + .Anchor (leftMin, leftMax) + .SizeDelta (0, 0) + .PreferredWidth(0) .Finish() .Add (out finalizeButton) .Text (ELLocalization.FinalizeBuild) .OnClick (FinalizeBuild) - .FlexibleLayout (true, true) + .Anchor (leftMin, leftMax) + .SizeDelta (0, 0) .Finish() .Add (out cancelButton) .Text (CancelRestartText ()) .OnClick (CancelRestart) - .FlexibleLayout (true, true) + .Anchor (rightMin, rightMax) + .SizeDelta (0, 0) .Finish() .Finish() .Finish(); From 2c0ed59fab7d33c603ceadfb47fb246ed05c708f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 21:05:43 +0900 Subject: [PATCH 030/150] Balance the pause and cancel buttons --- KodeUI | 2 +- Source/UI/CraftView.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/KodeUI b/KodeUI index 1ffabe72..14705ae8 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 1ffabe727c8320cd0886a4360fe9f6b7f8b19eb9 +Subproject commit 14705ae8478db5c58fde7436e225024831ccc00f diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index 30979161..7c91cf10 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -222,6 +222,8 @@ public override void CreateUI() craftBoM.tmpText.overflowMode = TextOverflowModes.Linked; craftBoM.tmpText.linkedTextComponent = overflowText.tmpText; + + selectFlagButton.ChildImage.AspectRatioSizeFitter (AspectRatioFitter.AspectMode.FitInParent, 1.6f); } void BuildCraft () From 55c63f649ffd9dd350c30464713ee305b5a5f8f5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 23:15:41 +0900 Subject: [PATCH 031/150] Nuke BaseResourceLine It turned out to be more trouble than it was worth. --- Source/UI/BuildView.cs | 32 +++++++++++++++++++------------- Source/UI/CraftView.cs | 22 +++++++++++++++------- Source/UI/IResourceLine.cs | 2 +- Source/UI/ResourceDisplay.cs | 24 ------------------------ Source/UI/ResourceLine.cs | 16 ++++++++-------- 5 files changed, 43 insertions(+), 53 deletions(-) diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index 457c507a..e502bedf 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -34,12 +34,15 @@ namespace ExtraplanetaryLaunchpads { public class ELBuildView : Layout { - public class ProgressResource : ELResourceDisplay.BaseResourceLine + public class ProgressResource : IResourceLine { ELBuildControl control; - BuildResource requiredResource; + BuildResource built; + BuildResource required; + RMResourceInfo available; - public override string ResourceInfo + public string ResourceName { get { return built.name; } } + public string ResourceInfo { get { if (control.paused) { @@ -54,11 +57,13 @@ public override string ResourceInfo return percent; } } - public override double ResourceFraction + public double BuildAmount { get { return built.amount; } } + public double AvailableAmount { get { return available.amount; } } + public double ResourceFraction { get { - double required = requiredResource.amount; - double built = RequiredAmount; + double required = this.required.amount; + double built = this.built.amount; if (required < 0) { return 0; @@ -74,24 +79,25 @@ public override double ResourceFraction } public ProgressResource (BuildResource built, BuildResource required, RMResourceInfo pad, ELBuildControl control) - : base (built, pad) { + this.built = built; + this.required = required; + this.available = pad; this.control = control; - requiredResource = required; } public double CalculateETA () { double frames; - if (buildResource.deltaAmount <= 0) { + if (built.deltaAmount <= 0) { return 0; } if (control.state == ELBuildControl.State.Building) { - frames = buildResource.amount / buildResource.deltaAmount; + frames = built.amount / built.deltaAmount; } else { - double remaining = buildResource.amount; - remaining -= requiredResource.amount; - frames = remaining / buildResource.deltaAmount; + double remaining = built.amount; + remaining -= required.amount; + frames = remaining / built.deltaAmount; } return frames * TimeWarp.fixedDeltaTime; } diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index 7c91cf10..d2165836 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -34,14 +34,20 @@ namespace ExtraplanetaryLaunchpads { public class ELCraftView : Layout { - class RequiredResource : ELResourceDisplay.BaseResourceLine + class RequiredResource : IResourceLine { - public override string ResourceInfo { get { return null; } } - public override double ResourceFraction + BuildResource required; + RMResourceInfo available; + + public string ResourceName { get { return required.name; } } + public string ResourceInfo { get { return null; } } + public double BuildAmount { get { return required.amount; } } + public double AvailableAmount { get { return available.amount; } } + public double ResourceFraction { get { - double required = RequiredAmount; - double available = AvailableAmount; + double required = this.required.amount; + double available = this.available.amount; if (available < 0) { return 0; @@ -53,8 +59,10 @@ public override double ResourceFraction } public RequiredResource (BuildResource build, RMResourceInfo pad) - : base (build, pad) - { } + { + this.required = build; + this.available = pad; + } } Sprite flagTexture; diff --git a/Source/UI/IResourceLine.cs b/Source/UI/IResourceLine.cs index ef2b2467..f85dd8d5 100644 --- a/Source/UI/IResourceLine.cs +++ b/Source/UI/IResourceLine.cs @@ -30,7 +30,7 @@ public interface IResourceLine string ResourceName { get; } string ResourceInfo { get; } double ResourceFraction { get; } - double RequiredAmount { get; } + double BuildAmount { get; } double AvailableAmount { get; } } } diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs index 05522323..8fb9961b 100644 --- a/Source/UI/ResourceDisplay.cs +++ b/Source/UI/ResourceDisplay.cs @@ -31,30 +31,6 @@ namespace ExtraplanetaryLaunchpads { public class ELResourceDisplay : Layout { - public abstract class BaseResourceLine : IResourceLine - { - protected string name; - protected BuildResource buildResource; - protected RMResourceInfo padResource; - - public virtual string ResourceName { get { return name; } } - public abstract string ResourceInfo { get; } - public abstract double ResourceFraction { get; } - public virtual double RequiredAmount { - get { return buildResource.amount; } - } - public virtual double AvailableAmount { - get { return padResource != null ? padResource.amount : 0; } - } - - public BaseResourceLine (BuildResource build, RMResourceInfo pad) - { - name = build.name; - buildResource = build; - padResource = pad; - } - } - List resources; public override void CreateUI() diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index 8e647b7b..36225065 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -30,12 +30,12 @@ public class ELResourceLine : LayoutAnchor UIText resourceName; UISlider fraction; UIText info; - UIText required; + UIText amount; UIText available; IResourceLine resource; - string displayAmount (double amount) { + static string displayAmount (double amount) { if (amount > 1e5) { return Math.Round((amount / 1e6), 2).ToString() + " M"; } else { @@ -51,20 +51,20 @@ public void UpdateDisplay() double frac = resource.ResourceFraction; fraction.slider.SetValueWithoutNotify ((float) frac); - double required = resource.RequiredAmount; + double amount = resource.BuildAmount; double available = resource.AvailableAmount; if (available >= 0) { this.available.Text (displayAmount (available)); } Color color = UnityEngine.Color.green; - if (available >= 0 && available < required) { + if (available >= 0 && available < amount) { color = UnityEngine.Color.yellow; } else if (available < 0) { color = UnityEngine.Color.white; } - this.required.Color(color).Style(); - this.required.Text (displayAmount (required)); + this.amount.Color(color).Style(); + this.amount.Text (displayAmount (amount)); } public override void CreateUI() @@ -136,7 +136,7 @@ public override void CreateUI() .Anchor (AnchorPresets.StretchAll) .SizeDelta (0, 0) .Finish() - .Add (out required) + .Add (out amount) .Text ("500") .Size (12) .Margin (textMargins) @@ -179,7 +179,7 @@ public ELResourceLine Resource (IResourceLine resource) { this.resource = resource; resourceName.Text (resource.ResourceName); - required.Text (displayAmount (resource.RequiredAmount)); + amount.Text (displayAmount (resource.BuildAmount)); if (resource.AvailableAmount >= 0) { available.Text (displayAmount (resource.AvailableAmount)); } else { From 2bee2d9c9452c4627d831d3d855296dac06be002 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 3 Oct 2020 23:56:44 +0900 Subject: [PATCH 032/150] Implement the basics of the transfer view Other than linked resources, this makes the new build window feature-complete. --- KodeUI | 2 +- Source/Makefile | 1 + Source/UI/IResourceLine.cs | 5 + Source/UI/Localization.cs | 1 + Source/UI/MainWindow.cs | 5 + Source/UI/ResourceDisplay.cs | 2 +- Source/UI/ResourceLine.cs | 10 ++ Source/UI/TransferView.cs | 201 +++++++++++++++++++++++++++++++++++ 8 files changed, 225 insertions(+), 2 deletions(-) create mode 100644 Source/UI/TransferView.cs diff --git a/KodeUI b/KodeUI index 14705ae8..6352d874 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 14705ae8478db5c58fde7436e225024831ccc00f +Subproject commit 6352d874986fc49cdb0c6df4b81ec6c4fc83650b diff --git a/Source/Makefile b/Source/Makefile index 6fcb4dd3..8dc1ce10 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -83,6 +83,7 @@ EL_FILES := \ UI/ResourceDisplay.cs \ UI/ResourceLine.cs \ UI/StatusBar.cs \ + UI/TransferView.cs \ Workshop/ConstructionSkill.cs \ Workshop/ProtoWorkSink.cs \ Workshop/VesselWorkNet.cs \ diff --git a/Source/UI/IResourceLine.cs b/Source/UI/IResourceLine.cs index f85dd8d5..e717d95d 100644 --- a/Source/UI/IResourceLine.cs +++ b/Source/UI/IResourceLine.cs @@ -33,4 +33,9 @@ public interface IResourceLine double BuildAmount { get; } double AvailableAmount { get; } } + + public interface IResourceLineAdjust + { + double ResourceFraction { set; } + } } diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 83e7c4b6..12572963 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -46,5 +46,6 @@ public static class ELLocalization public static string CancelBuild { get; } = "Cancel Build"; public static string RestartBuild { get; } = "Restart Build"; public static string Paused { get; } = "[paused]"; + public static string Release { get; } = "Release"; } } diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index fbdfa2ad..ca269224 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -34,6 +34,7 @@ public class ELMainWindow : Window ELPadView padView; ELCraftView craftView; ELBuildView buildView; + ELTransferView transferView; public override void CreateUI() { @@ -55,12 +56,16 @@ public override void CreateUI() .Finish() .Add(out buildView, "BuildView") .Finish() + .Add(out transferView, "TransferView") + .Finish() .Finish(); craftView.gameObject.SetActive (false); buildView.gameObject.SetActive (false); + transferView.gameObject.SetActive (false); padView.AddListener (craftView.UpdateControl); padView.AddListener (buildView.UpdateControl); + padView.AddListener (transferView.UpdateControl); } public override void Style () diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs index 8fb9961b..b8598a47 100644 --- a/Source/UI/ResourceDisplay.cs +++ b/Source/UI/ResourceDisplay.cs @@ -35,7 +35,7 @@ public class ELResourceDisplay : Layout public override void CreateUI() { - this.Horizontal () + this.Vertical () .ChildForceExpand(false,false) .FlexibleLayout (true, false) .SizeDelta (0, 0); diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index 36225065..d6de6f6b 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -113,6 +113,7 @@ public override void CreateUI() .Add (out fraction, "ResourceFraction") .Direction (Slider.Direction.LeftToRight) .ShowHandle (false) + .OnValueChanged (OnFractionChanged) .Anchor (AnchorPresets.StretchAll) .SizeDelta (0, 0) .Finish () @@ -168,6 +169,7 @@ public override void CreateUI() .Finish (); fraction.interactable = false; fraction.slider.SetValueWithoutNotify(0.5f); + info.tmpText.raycastTarget = false; } public override void Style () @@ -175,6 +177,11 @@ public override void Style () base.Style (); } + void OnFractionChanged (float frac) + { + (resource as IResourceLineAdjust).ResourceFraction = frac; + } + public ELResourceLine Resource (IResourceLine resource) { this.resource = resource; @@ -185,6 +192,9 @@ public ELResourceLine Resource (IResourceLine resource) } else { available.Text (ELLocalization.NotAvailable); } + bool adjust = resource is IResourceLineAdjust; + fraction.ShowHandle (adjust); + fraction.interactable = adjust; return this; } diff --git a/Source/UI/TransferView.cs b/Source/UI/TransferView.cs new file mode 100644 index 00000000..d60202f7 --- /dev/null +++ b/Source/UI/TransferView.cs @@ -0,0 +1,201 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ELTransferView : Layout + { + public class TransferResource : IResourceLine, IResourceLineAdjust + { + ELBuildControl control; + BuildResource optional; + RMResourceInfo capacity; + RMResourceInfo available; + + public string ResourceName { get { return optional.name; } } + public string ResourceInfo + { + get { + return null; + } + } + public double BuildAmount { get { return optional.amount; } } + public double AvailableAmount { get { return available.amount; } } + public double ResourceFraction + { + get { + return optional.amount / capacity.maxAmount; + } + set { + optional.amount = value * capacity.maxAmount; + } + } + + public TransferResource (BuildResource opt, RMResourceInfo cap, RMResourceInfo pad, ELBuildControl control) + { + optional = opt; + capacity = cap; + available = pad; + this.control = control; + } + } + + UIButton releaseButton; + + ScrollView craftView; + Layout selectedCraft; + ELResourceDisplay resourceList; + UIText craftName; + + List transferResources; + + ELBuildControl control; + + public override void CreateUI() + { + if (transferResources == null) { + transferResources = new List (); + } + + base.CreateUI (); + + var leftMin = new Vector2 (0, 0); + var leftMax = new Vector2 (0.5f, 1); + var rightMin = new Vector2 (0.5f, 0); + var rightMax = new Vector2 (1, 1); + + UIScrollbar scrollbar; + Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add() + .Background("KodeUI/Default/background") + .BackgroundColor(UnityEngine.Color.white) + .Vertical() + .Padding(8) + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .Anchor(AnchorPresets.HorStretchTop) + .FlexibleLayout(true,true) + .PreferredHeight(300) + .Add (out selectedCraft) + .Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .FlexibleLayout(true,false) + .Add () + .Text (ELLocalization.SelectedCraft) + .Finish () + .Add() + .MinSize(15,-1) + .Finish() + .Add (out craftName) + .Finish () + .Finish () + .Add (out craftView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Add (out scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () + .Add (out releaseButton) + .Text (ELLocalization.Release) + .OnClick (ReleaseCraft) + .FlexibleLayout (true, true) + .Finish() + .Finish(); + + craftView.VerticalScrollbar = scrollbar; + craftView.Viewport.FlexibleLayout (true, true); + craftView.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .WidthDelta(0) + .Add (out resourceList) + .Finish () + .Finish (); + } + + void ReleaseCraft () + { + control.ReleaseVessel (); + } + + public void UpdateControl (ELBuildControl control) + { + this.control = control; + if (control != null + && (control.state == ELBuildControl.State.Transfer)) { + gameObject.SetActive (true); + craftName.Text (control.craftName); + StartCoroutine (WaitAndRebuildResources ()); + } else { + gameObject.SetActive (false); + } + } + + static BuildResource FindResource (List reslist, string name) + { + return reslist.Where(r => r.name == name).FirstOrDefault (); + } + + void RebuildResources () + { + transferResources.Clear (); + foreach (var res in control.buildCost.optional) { + var opt = control.craftResources[res.name]; + var available = control.padResources[res.name]; + var line = new TransferResource (res, opt, available, control); + transferResources.Add (line); + } + resourceList.Resources (transferResources); + } + + IEnumerator WaitAndRebuildResources () + { + while (control.padResources == null) { + yield return null; + } + RebuildResources (); + } + } +} From 738eb0d20c013f373b504e885de12c1cf11f8207 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 12:11:38 +0900 Subject: [PATCH 033/150] Fix difficulty dragging windows The window title text was blocking the dragger. --- KodeUI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/KodeUI b/KodeUI index 6352d874..637e78cb 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 6352d874986fc49cdb0c6df4b81ec6c4fc83650b +Subproject commit 637e78cbbd56274829786c17f41b0bdba33b255d From 15d2914325b20ff521cb44d16d61cfc49b04fed5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 14:59:05 +0900 Subject: [PATCH 034/150] Replace old BuildWindow with new MainWindow ELMainWindow might get renamed later, but it seems to be working nicely with app launcher toggle and PAW show/hide buttons, and pad renaming works nicely, too :) --- Source/BuildControl.cs | 19 +- Source/DisposablePad/DisposablePad.cs | 10 +- Source/GUI/BuildWindow.cs | 899 -------------------------- Source/Makefile | 5 +- Source/Pad/Launchpad.cs | 10 +- Source/Settings.cs | 8 +- Source/Survey/SurveyStation.cs | 10 +- Source/UI/MainWindow.cs | 6 + Source/UI/PadView.cs | 66 +- Source/UI/WindowManager.cs | 133 ++++ Source/toolbar/Toolbar.cs | 6 +- 11 files changed, 241 insertions(+), 931 deletions(-) delete mode 100644 Source/GUI/BuildWindow.cs create mode 100644 Source/UI/WindowManager.cs diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index c213f9fc..8a1147fe 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -30,6 +30,7 @@ namespace ExtraplanetaryLaunchpads { public class ELBuildControl : ELWorkSink { public static readonly EventData onBuildStateChanged = new EventData ("onBuildStateChanged"); + public static readonly EventData onPadRenamed = new EventData ("onPadRenamed"); public interface IBuilder { @@ -189,6 +190,11 @@ public bool isActive } } + static BuildResource FindResource (List reslist, string name) + { + return reslist.Where(r => r.name == name).FirstOrDefault (); + } + public double CalculateWork () { if (paused) { @@ -205,7 +211,7 @@ public double CalculateWork () } else if (state == State.Canceling) { for (int i = built.Count; i-- > 0; ) { var res = built[i]; - var cres = ELBuildWindow.FindResource (cost, res.name); + var cres = FindResource (cost, res.name); hours += res.kerbalHours * (cres.amount - res.amount); } } @@ -243,7 +249,7 @@ void SetPadMass () var cost = buildCost.required; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); mass += (cres.amount - bres.amount) * bres.density; } } @@ -331,7 +337,7 @@ int CountResources (List built, List cost) { int count = 0; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); if (cres.amount - bres.amount > 0) { count++; } @@ -361,7 +367,7 @@ private void DoWork_Cancel (double kerbalHours) did_work = false; foreach (var bres in built) { - var cres = ELBuildWindow.FindResource (cost, bres.name); + var cres = FindResource (cost, bres.name); double remaining = cres.amount - bres.amount; if (remaining <= 0) { continue; @@ -984,6 +990,11 @@ internal void OnDestroy () DestroyCraftHull (); } + public void OnRename (string oldName) + { + onPadRenamed.Fire (this, oldName, builder.Name); + } + void CleanupAfterRelease () { craftRoot = null; diff --git a/Source/DisposablePad/DisposablePad.cs b/Source/DisposablePad/DisposablePad.cs index 1c92fe8a..50538063 100644 --- a/Source/DisposablePad/DisposablePad.cs +++ b/Source/DisposablePad/DisposablePad.cs @@ -30,6 +30,7 @@ public class ELDisposablePad : PartModule, IModuleInfo, IPartMassModifier, ELBui public string SpawnTransform; [KSPField (isPersistant = true, guiActive = true, guiName = "Pad name")] public string PadName = ""; + string oldName = ""; [KSPField (isPersistant = true)] public bool Operational = true; @@ -324,6 +325,7 @@ public override void OnStart (PartModule.StartState state) EL_Utils.SetupEVAEvent (Events["ShowRenameUI"], EVARange); } control.OnStart (); + UpdateMenus (false); } void OnDestroy () @@ -336,20 +338,20 @@ void OnDestroy () [KSPEvent (guiActive = true, guiName = "Hide UI", active = false)] public void HideUI () { - ELBuildWindow.HideGUI (); + ELWindowManager.HideBuildWindow (); } [KSPEvent (guiActive = true, guiName = "Show UI", active = false)] public void ShowUI () { - ELBuildWindow.ShowGUI (); - ELBuildWindow.SelectPad (control); + ELWindowManager.ShowBuildWindow (control); } [KSPEvent (guiActive = true, guiActiveEditor = true, guiName = "Rename", active = true)] public void ShowRenameUI () { + oldName = PadName; ELRenameWindow.ShowGUI (this); } @@ -388,7 +390,7 @@ public double CalculateWork () public void OnRename () { - ELBuildWindow.updateCurrentPads (); + control.OnRename (oldName); } } } diff --git a/Source/GUI/BuildWindow.cs b/Source/GUI/BuildWindow.cs deleted file mode 100644 index afb82e79..00000000 --- a/Source/GUI/BuildWindow.cs +++ /dev/null @@ -1,899 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KodeUI; - -using KSP.IO; -using KSP.UI.Screens; - -using ExtraplanetaryLaunchpads_KACWrapper; - -namespace ExtraplanetaryLaunchpads { - - [KSPAddon (KSPAddon.Startup.Flight, false)] - public class ELBuildWindow : MonoBehaviour - { - static ELBuildWindow instance; - static bool hide_ui = false; - static bool gui_enabled = true; - static Rect windowpos; - static bool highlight_pad = true; - static bool link_lfo_sliders = true; - static double minimum_alarm_time = 60; - - static ELCraftBrowser craftlist = null; - static ELScrollView resScroll = new ELScrollView (680,300); - - static FlagBrowser flagBrowserPrefab; - static FlagBrowser flagBrowser; - static string flagURL; - static Texture2D flagTexture; - - List launchpads; - Vessel vessel; - ELVesselWorkNet worknet; - DropDownList pad_list; - ELBuildControl control; - - static GUILayoutOption width48 = GUILayout.Width (48); - static GUILayoutOption width100 = GUILayout.Width (100); - static GUILayoutOption width125 = GUILayout.Width (125); - static GUILayoutOption width300 = GUILayout.Width (300); - static GUILayoutOption width695 = GUILayout.Width (695); - static GUILayoutOption height20 = GUILayout.Height (20); - static GUILayoutOption height32 = GUILayout.Height (32); - static GUILayoutOption height40 = GUILayout.Height (40); - static GUILayoutOption expandWidth = GUILayout.ExpandWidth (true); - static GUILayoutOption noExpandWidth = GUILayout.ExpandWidth (false); - - //FIXME this is a workaround for a bug in KSP 1.3.1 and earlier - void VMSaveHack (Vessel o, Vessel n) - { - for (int i = 0; i < FlightGlobals.Vessels.Count; i++) { - Vessel v = FlightGlobals.Vessels[i]; - if (!v.loaded) { - v.protoVessel.SaveVesselModules (); - } - } - } - - static bool KACinited = false; - - internal void Start() - { - if (!KACinited) { - KACinited = true; - KACWrapper.InitKACWrapper(); - } - if (KACWrapper.APIReady) - { - //All good to go - Debug.Log ("KACWrapper initialized"); - } - - if (flagBrowserPrefab == null) { - var fbObj = AssetBase.GetPrefab ("FlagBrowser"); - flagBrowserPrefab = fbObj.GetComponent (); - } - } - - public static void ToggleGUI () - { - gui_enabled = !gui_enabled; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void HideGUI () - { - gui_enabled = false; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void ShowGUI () - { - gui_enabled = true; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void LoadSettings (ConfigNode node) - { - string val = node.GetValue ("rect"); - if (val != null) { - Quaternion pos; - pos = ConfigNode.ParseQuaternion (val); - windowpos.x = pos.x; - windowpos.y = pos.y; - windowpos.width = pos.z; - windowpos.height = pos.w; - } - val = node.GetValue ("visible"); - if (val != null) { - bool.TryParse (val, out gui_enabled); - } - val = node.GetValue ("link_lfo_sliders"); - if (val != null) { - bool.TryParse (val, out link_lfo_sliders); - } - val = node.GetValue ("minimum_alarm_time"); - if (val != null) { - double.TryParse (val, out minimum_alarm_time); - } - } - - public static void SaveSettings (ConfigNode node) - { - Quaternion pos; - pos.x = windowpos.x; - pos.y = windowpos.y; - pos.z = windowpos.width; - pos.w = windowpos.height; - node.AddValue ("rect", KSPUtil.WriteQuaternion (pos)); - node.AddValue ("visible", gui_enabled); - node.AddValue ("link_lfo_sliders", link_lfo_sliders); - } - - static ELVesselWorkNet FindWorkNet (Vessel v) - { - for (int i = 0; i < v.vesselModules.Count; i++) { - var worknet = v.vesselModules[i] as ELVesselWorkNet; - if (worknet != null) { - return worknet; - } - } - return null; - } - - static ELBuildControl FindControl (Vessel v, uint id) - { - Part part = v[id]; - if (part != null) { - var pad = part.FindModuleImplementing (); - if (pad != null) { - return pad.control; - } - } - return null; - } - - void BuildPadList (Vessel v) - { - launchpads = null; - pad_list = null; - worknet = null; - - if (v.isEVA) { - control = null; - return; - } - var pads = v.FindPartModulesImplementing (); - if (pads.Count < 1) { - control = null; - } else { - worknet = FindWorkNet (v); - if (worknet != null) { - control = FindControl (v, worknet.selectedPad); - } - launchpads = new List (); - int control_index = -1; - for (int i = 0; i < pads.Count; i++) { - launchpads.Add (pads[i].control); - if (control == pads[i].control) { - control_index = i; - } - } - if (control_index < 0) { - control_index = 0; - control = pads[0].control; - } - var pad_names = new List (); - for (int ind = 0; ind < launchpads.Count; ind++) { - var p = launchpads[ind]; - if (p.builder.Name != "") { - pad_names.Add (p.builder.Name); - } else { - pad_names.Add ("pad-" + ind); - } - } - pad_list = new DropDownList (pad_names); - - Select_Pad (launchpads[control_index]); - } - } - - void onVesselChange (Vessel v) - { - BuildPadList (v); - UpdateGUIState (); - vessel = v; - mainWindow.SetVessel(vessel); - } - - void onVesselWasModified (Vessel v) - { - if (FlightGlobals.ActiveVessel == v) { - BuildPadList (v); - UpdateGUIState (); - } - } - - static public void updateCurrentPads() { - if (instance != null) { - instance.BuildPadList (FlightGlobals.ActiveVessel); - } - } - - void UpdateGUIState () - { - bool old = enabled; - enabled = !hide_ui && launchpads != null && gui_enabled; - if (control != null) { - control.builder.Highlight (enabled && highlight_pad); - if (enabled) { - UpdateFlagTexture (); - } - } - if (launchpads != null) { - for (int i = 0; i < launchpads.Count; i++) { - var p = launchpads[i]; - p.builder.UpdateMenus (enabled && p == control); - } - } - if (!mainWindow) { - mainWindow = UIKit.CreateUI (appCanvas.transform as RectTransform, "ELMainWindow"); - } - if (old != enabled) { - mainWindow.gameObject.SetActive(enabled); - mainWindow.SetVessel (vessel); - } - } - - void UpdateFlagTexture () - { - flagURL = control.flagname; - - if (String.IsNullOrEmpty (flagURL)) { - flagURL = control.builder.part.flagURL; - } - - flagTexture = GameDatabase.Instance.GetTexture (flagURL, false); - } - - void CreateFlagBrowser () - { - flagBrowser = Instantiate (flagBrowserPrefab); - - flagBrowser.OnDismiss = OnFlagCancel; - flagBrowser.OnFlagSelected = OnFlagSelected; - } - - void onHideUI () - { - hide_ui = true; - UpdateGUIState (); - } - - void onShowUI () - { - hide_ui = false; - UpdateGUIState (); - } - - Canvas appCanvas; - ELMainWindow mainWindow; - - void Awake () - { - appCanvas = DialogCanvasUtil.DialogCanvas; - instance = this; - GameEvents.onVesselChange.Add (onVesselChange); - GameEvents.onVesselWasModified.Add (onVesselWasModified); - GameEvents.onHideUI.Add (onHideUI); - GameEvents.onShowUI.Add (onShowUI); - GameEvents.onVesselSwitchingToUnloaded.Add (VMSaveHack); - enabled = false; - } - - void OnDestroy () - { - instance = null; - GameEvents.onVesselChange.Remove (onVesselChange); - GameEvents.onVesselWasModified.Remove (onVesselWasModified); - GameEvents.onHideUI.Remove (onHideUI); - GameEvents.onShowUI.Remove (onShowUI); - GameEvents.onVesselSwitchingToUnloaded.Remove (VMSaveHack); - if (mainWindow) { - Destroy (mainWindow.gameObject); - mainWindow = null; - } - } - - float ResourceLine (string label, string resourceName, float fraction, - double minAmount, double maxAmount, - double available) - { - GUILayout.BeginHorizontal (); - - // Resource name - GUILayout.Box (label, ELStyles.white, width125, height40); - - // Fill amount - // limit slider to 0.5% increments - GUILayout.BeginVertical (); - if (minAmount == maxAmount) { - GUILayout.Box ("Must be 100%", width300, height20); - fraction = 1; - } else { - fraction = GUILayout.HorizontalSlider (fraction, 0.0F, 1.0F, - ELStyles.slider, - GUI.skin.horizontalSliderThumb, - width300, height20); - fraction = (float)Math.Round (fraction, 3); - fraction = (Mathf.Floor (fraction * 200)) / 200; - GUILayout.Box ((fraction * 100).ToString () + "%", - ELStyles.sliderText, width300, height20); - } - GUILayout.EndVertical (); - - double required = minAmount + (maxAmount - minAmount) * fraction; - - // Calculate if we have enough resources to build - GUIStyle requiredStyle = ELStyles.green; - if (available >= 0 && available < required) { - requiredStyle = ELStyles.yellow; - } - // Required and Available - GUILayout.Box (displayAmount(required), - requiredStyle, width100, height40); - if (available >= 0) { - GUILayout.Box (displayAmount(available), - ELStyles.white, width100, height40); - } else { - GUILayout.Box ("N/A", ELStyles.white, width100, height40); - } - - GUILayout.FlexibleSpace (); - - GUILayout.EndHorizontal (); - - return fraction; - } - - string displayAmount(double amount) { - if (amount > 1000000) { - return Math.Round((amount / 1000000), 2).ToString() + " M"; - } - else { - return Math.Round(amount, 2).ToString(); - } - } - - double BuildETA (BuildResource br, BuildResource req, bool forward) - { - double numberOfFramesLeft; - if (br.deltaAmount <= 0) { - return 0; - } - if (forward) { - numberOfFramesLeft = (br.amount / br.deltaAmount); - } else { - numberOfFramesLeft = ((req.amount-br.amount) / br.deltaAmount); - } - return numberOfFramesLeft * TimeWarp.fixedDeltaTime; - } - - double ResourceProgress (string label, BuildResource br, - BuildResource req, bool forward) - { - double fraction = 1; - if (req.amount > 0) { - fraction = (req.amount - br.amount) / req.amount; - } - double required = br.amount; - double available = control.padResources.ResourceAmount (br.name); - double eta = 0; - string percent = (fraction * 100).ToString ("G4") + "%"; - if (control.paused) { - percent = percent + "[paused]"; - } else { - eta = BuildETA (br, req, forward); - percent = percent + " " + EL_Utils.TimeSpanString (eta); - - } - - GUILayout.BeginHorizontal (); - - // Resource name - GUILayout.Box (label, ELStyles.white, width125, height40); - - GUILayout.BeginVertical (); - - ELStyles.bar.Draw ((float) fraction, percent, 300); - GUILayout.EndVertical (); - - // Calculate if we have enough resources to build - GUIStyle requiredStyle = ELStyles.green; - if (required > available) { - requiredStyle = ELStyles.yellow; - } - // Required and Available - GUILayout.Box (displayAmount(required), - requiredStyle, width100, height40); - GUILayout.Box (displayAmount(available), - ELStyles.white, width100, height40); - GUILayout.FlexibleSpace (); - - GUILayout.EndHorizontal (); - return eta; - } - - void SelectPad_start () - { - if (pad_list != null) { - pad_list.styleListItem = ELStyles.listItem; - pad_list.styleListBox = ELStyles.listBox; - pad_list.DrawBlockingSelector (); - control.builder.PadSelection_start (); - } - } - - public static void SelectPad (ELBuildControl selected_pad) - { - if (instance != null) { - instance.Select_Pad (selected_pad); - } - } - - void Select_Pad (ELBuildControl selected_pad) - { - if (control != null && control != selected_pad) { - control.builder.Highlight (false); - } - control = selected_pad; - worknet.selectedPad = control.builder.ID; - pad_list.SelectItem (launchpads.IndexOf (control)); - UpdateGUIState (); - } - - void VesselName () - { - GUILayout.BeginHorizontal (); - GUILayout.Label (control.builder.vessel.vesselName); - GUILayout.FlexibleSpace (); - GUILayout.Label (control.builder.vessel.situation.ToString ()); - double productivity = control.productivity; - GUIStyle prodStyle = ELStyles.green; - if (productivity <= 0) { - prodStyle = ELStyles.red; - } else if (productivity < 1) { - prodStyle = ELStyles.yellow; - } - GUILayout.Label ("Productivity: " + productivity.ToString("G3"), - prodStyle); - GUILayout.EndHorizontal (); - } - - void SelectPad () - { - GUILayout.BeginHorizontal (); - pad_list.DrawButton (); - highlight_pad = GUILayout.Toggle (highlight_pad, "Highlight Pad"); - Select_Pad (launchpads[pad_list.SelectedIndex]); - GUILayout.EndHorizontal (); - control.builder.PadSelection (); - } - - void SelectPad_end () - { - if (pad_list != null) { - pad_list.DrawDropDown(); - pad_list.CloseOnOutsideClick(); - control.builder.PadSelection_end (); - } - } - - void SelectCraft () - { - string strpath = HighLogic.SaveFolder; - - GUILayout.BeginHorizontal (); - GUI.enabled = craftlist == null; - if (GUILayout.Button ("Select Craft", ELStyles.normal, - expandWidth)) { - - //GUILayout.Button is "true" when clicked - craftlist = ELCraftBrowser.Spawn (control.craftType, - strpath, - craftSelectComplete, - craftSelectCancel, - false); - } - GUI.enabled = flagBrowser == null; - if (GUILayout.Button (flagTexture, ELStyles.normal, - width48, height32, noExpandWidth)) { - CreateFlagBrowser (); - } - GUI.enabled = control.craftConfig != null; - if (GUILayout.Button ("Reload", ELStyles.normal, noExpandWidth)) { - control.LoadCraft (control.filename, control.flagname); - } - if (GUILayout.Button ("Clear", ELStyles.normal, noExpandWidth)) { - control.UnloadCraft (); - } - GUI.enabled = true; - GUILayout.EndHorizontal (); - } - - void SelectedCraft () - { - if (control.craftConfig != null) { - var ship_name = control.craftName; - GUILayout.Box ("Selected Craft: " + ship_name, ELStyles.white); - } - } - - void LockedParts () - { - GUILayout.Label ("Not all of the blueprints for this vessel can be found."); - } - - void ResourceHeader (string header) - { - GUILayout.BeginHorizontal (); - GUILayout.Label (header, ELStyles.label, noExpandWidth); - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - } - - void RequiredResources () - { - if (control.padResources == null) { - return; - } - ResourceHeader ("Resources required to build:"); - foreach (var br in control.buildCost.required) { - double a = br.amount; - double available = -1; - - available = control.padResources.ResourceAmount (br.name); - ResourceLine (br.name, br.name, 1.0f, a, a, available); - } - } - - void BuildButton () - { - GUI.enabled = control.builder.canBuild; - if (GUILayout.Button ("Build", ELStyles.normal, expandWidth)) { - control.BuildCraft (); - } - GUI.enabled = true; - } - - void FinalizeButton () - { - GUILayout.BeginHorizontal (); - GUI.enabled = control.builder.canBuild; - if (GUILayout.Button ("Finalize Build", ELStyles.normal, - expandWidth)) { - control.BuildAndLaunchCraft (); - } - GUI.enabled = true; - if (GUILayout.Button ("Teardown Build", ELStyles.normal, - expandWidth)) { - control.CancelBuild (); - } - GUILayout.EndHorizontal (); - } - - internal static BuildResource FindResource (List reslist, string name) - { - return reslist.Where(r => r.name == name).FirstOrDefault (); - } - - void UpdateAlarm (double mostFutureAlarmTime, bool forward) - { - if (KACWrapper.APIReady && ELSettings.use_KAC) { - if (control.paused) { - // It doesn't make sense to have an alarm for an event that will never happen - if (control.KACalarmID != "") { - try { - KACWrapper.KAC.DeleteAlarm (control.KACalarmID); - } - catch { - // Don't crash if there was some problem deleting the alarm - } - control.KACalarmID = ""; - } - } else if (mostFutureAlarmTime>0) { - // Find the existing alarm, if it exists - // Note that we might have created an alarm, and then the user deleted it! - KACWrapper.KACAPI.KACAlarmList alarmList = KACWrapper.KAC.Alarms; - KACWrapper.KACAPI.KACAlarm a = null; - if ((alarmList != null) && (control.KACalarmID != "")) { - //Debug.Log ("Searching for alarm with ID [" + control.KACalarmID + "]"); - a = alarmList.FirstOrDefault (z => z.ID == control.KACalarmID); - } - - // set up the strings for the alarm - string builderShipName = FlightGlobals.ActiveVessel.vesselName; - string newCraftName = control.craftConfig.GetValue ("ship"); - - string alarmMessage = "[EL] build: \"" + newCraftName + "\""; - string alarmNotes = "Completion of Extraplanetary Launchpad build of \"" + newCraftName + "\" on \"" + builderShipName + "\""; - if (!forward) { // teardown messages - alarmMessage = "[EL] teardown: \"" + newCraftName + "\""; - alarmNotes = "Teardown of Extraplanetary Launchpad build of \"" + newCraftName + "\" on \"" + builderShipName + "\""; - } - - if (a == null) { - // no existing alarm, make a new alarm - control.KACalarmID = KACWrapper.KAC.CreateAlarm (KACWrapper.KACAPI.AlarmTypeEnum.Raw, alarmMessage, mostFutureAlarmTime); - //Debug.Log ("new alarm ID: [" + control.KACalarmID + "]"); - - if (control.KACalarmID != "") { - a = KACWrapper.KAC.Alarms.FirstOrDefault (z => z.ID == control.KACalarmID); - if (a != null) { - a.AlarmAction = ELSettings.KACAction; - a.AlarmMargin = 0; - a.VesselID = FlightGlobals.ActiveVessel.id.ToString (); - } - } - } - if (a != null) { - // Whether we created an alarm or found an existing one, now update it - a.AlarmTime = mostFutureAlarmTime; - a.Notes = alarmNotes; - a.Name = alarmMessage; - } - } - } - } - - void BuildProgress (bool forward) - { - double longestETA = 0; - foreach (var br in control.builtStuff.required) { - var req = FindResource (control.buildCost.required, br.name); - double eta = ResourceProgress (br.name, br, req, forward); - if (eta > longestETA) { - longestETA = eta; - } - } - if (longestETA > 0 && longestETA > minimum_alarm_time) { - double alarmTime = Planetarium.GetUniversalTime () + longestETA; - UpdateAlarm (alarmTime, forward); - } - } - - void CraftBoM () - { - if (control.craftBoM == null) { - if (!control.CreateBoM ()) { - return; - } - } - for (int i = 0, count = control.craftBoM.Count; i < count; i++) { - GUILayout.Label (control.craftBoM[i]); - } - } - - void OptionalResources () - { - link_lfo_sliders = GUILayout.Toggle (link_lfo_sliders, - "Link LiquidFuel and " - + "Oxidizer sliders"); - foreach (var br in control.buildCost.optional) { - double available = control.padResources.ResourceAmount (br.name); - double maximum = control.craftResources.ResourceCapacity(br.name); - float frac = (float) (br.amount / maximum); - frac = ResourceLine (br.name, br.name, frac, 0, - maximum, available); - if (link_lfo_sliders - && (br.name == "LiquidFuel" || br.name == "Oxidizer")) { - string other; - if (br.name == "LiquidFuel") { - other = "Oxidizer"; - } else { - other = "LiquidFuel"; - } - var or = FindResource (control.buildCost.optional, other); - if (or != null) { - double om = control.craftResources.ResourceCapacity (other); - or.amount = om * frac; - } - } - br.amount = maximum * frac; - } - } - - static string[] state_str = { - "Build", "Teardown", - }; - void PauseButton () - { - int ind = control.state == ELBuildControl.State.Building ? 0 : 1; - string statestr = state_str[ind]; - GUILayout.BeginHorizontal (); - if (control.paused) { - if (GUILayout.Button ($"Resume {statestr}", ELStyles.normal, - expandWidth)) { - control.ResumeBuild (); - } - } else { - if (GUILayout.Button ($"Pause {statestr}", ELStyles.normal, - expandWidth)) { - control.PauseBuild (); - } - } - if (control.state == ELBuildControl.State.Building) { - if (GUILayout.Button ("Cancel Build", ELStyles.normal, - expandWidth)) { - control.CancelBuild (); - } - } else { - if (GUILayout.Button ("Restart Build", ELStyles.normal, - expandWidth)) { - control.UnCancelBuild (); - } - } - GUILayout.EndHorizontal (); - } - - void ReleaseButton () - { - if (GUILayout.Button ("Release", ELStyles.normal, expandWidth)) { - control.ReleaseVessel (); - } - } - - void CloseButton () - { - GUILayout.BeginHorizontal (); - GUILayout.FlexibleSpace (); - if (GUILayout.Button ("Close")) { - HideGUI (); - } - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - } - - void WindowGUI (int windowID) - { - var e = Event.current; - switch (e.type) { - case EventType.Layout: - if (control.craftBoMdirty) { - control.CreateBoM (); - } - break; - } - ELStyles.Init (); - - SelectPad_start (); - - GUILayout.BeginVertical (); - VesselName (); - SelectPad (); - - switch (control.state) { - case ELBuildControl.State.Idle: - SelectCraft (); - break; - case ELBuildControl.State.Planning: - SelectCraft (); - if (control.state != ELBuildControl.State.Planning) { - // the loaded craft was cleared - break; - } - SelectedCraft (); - if (control.lockedParts) { - resScroll.Begin (); - LockedParts (); - resScroll.End (); - } else { - resScroll.Begin (); - RequiredResources (); - CraftBoM (); - resScroll.End (); - BuildButton (); - } - break; - case ELBuildControl.State.Building: - SelectedCraft (); - resScroll.Begin (); - BuildProgress (true); - resScroll.End (); - PauseButton (); - break; - case ELBuildControl.State.Canceling: - SelectedCraft (); - resScroll.Begin (); - BuildProgress (false); - resScroll.End (); - PauseButton (); - break; - case ELBuildControl.State.Complete: - SelectedCraft (); - FinalizeButton (); - break; - case ELBuildControl.State.Transfer: - SelectedCraft (); - resScroll.Begin (); - OptionalResources (); - resScroll.End (); - ReleaseButton (); - break; - } - - GUILayout.EndVertical (); - - CloseButton (); - - SelectPad_end (); - - GUI.DragWindow (new Rect (0, 0, 10000, 20)); - - } - - void OnFlagCancel () - { - flagBrowser = null; - } - - void OnFlagSelected (FlagBrowser.FlagEntry selected) - { - control.flagname = selected.textureInfo.name; - flagTexture = selected.textureInfo.texture; - UpdateFlagTexture (); - flagBrowser = null; - } - - private void craftSelectComplete (string filename, - CraftBrowserDialog.LoadType lt) - { - control.craftType = craftlist.craftType; - craftlist = null; - - control.LoadCraft(filename, flagURL); - } - - private void craftSelectCancel () - { - craftlist = null; - } - - void OnGUI () - { - GUI.skin = HighLogic.Skin; - windowpos = GUILayout.Window (GetInstanceID (), - windowpos, WindowGUI, - ELVersionReport.GetVersion (), - width695); - } - } -} diff --git a/Source/Makefile b/Source/Makefile index 8dc1ce10..c5abffb4 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -38,6 +38,7 @@ EL_FILES := \ Recipes/RecipeResourceContainer.cs \ Recipes/RecipeDatabase.cs \ Recipes/RecipeLoader.cs \ + Recipes/ResourceLink.cs \ ResourceManager/IResourceContainer.cs \ ResourceManager/KISResourceContainer.cs \ ResourceManager/PartResourceContainer.cs \ @@ -58,7 +59,6 @@ EL_FILES := \ assembly/AssemblyInfo.cs \ assembly/Checkers.cs \ assembly/VersionReport.cs \ - GUI/BuildWindow.cs \ GUI/CraftBrowser.cs \ GUI/DropDownList.cs \ GUI/EditorToolbar.cs \ @@ -84,6 +84,7 @@ EL_FILES := \ UI/ResourceLine.cs \ UI/StatusBar.cs \ UI/TransferView.cs \ + UI/WindowManager.cs \ Workshop/ConstructionSkill.cs \ Workshop/ProtoWorkSink.cs \ Workshop/VesselWorkNet.cs \ @@ -160,7 +161,7 @@ bin/Launchpad.dll: ${EL_FILES} ${KodeUI} clean: rm -f ${TARGETS}* assembly/AssemblyInfo.cs bin/${MODNAME}.version - test -d bin && rmdir bin || true + rm -rf bin || true install: all mkdir -p ${PLUGINDIR} diff --git a/Source/Pad/Launchpad.cs b/Source/Pad/Launchpad.cs index 105344fa..17b3b0c9 100644 --- a/Source/Pad/Launchpad.cs +++ b/Source/Pad/Launchpad.cs @@ -32,6 +32,7 @@ public class ELLaunchpad : PartModule, IModuleInfo, IPartMassModifier, ELBuildCo public string SpawnTransform; [KSPField (isPersistant = true, guiActive = true, guiName = "Pad name")] public string PadName = ""; + string oldName = ""; [KSPField] public float EVARange = 0; @@ -270,6 +271,7 @@ public override void OnStart (PartModule.StartState state) EL_Utils.SetupEVAEvent (Events["ShowRenameUI"], EVARange); } control.OnStart (); + UpdateMenus (false); } void OnDestroy () @@ -282,20 +284,20 @@ void OnDestroy () [KSPEvent (guiActive = true, guiName = "Hide UI", active = false)] public void HideUI () { - ELBuildWindow.HideGUI (); + ELWindowManager.HideBuildWindow (); } [KSPEvent (guiActive = true, guiName = "Show UI", active = false)] public void ShowUI () { - ELBuildWindow.ShowGUI (); - ELBuildWindow.SelectPad (control); + ELWindowManager.ShowBuildWindow (control); } [KSPEvent (guiActive = true, guiActiveEditor = true, guiName = "Rename", active = true)] public void ShowRenameUI () { + oldName = PadName; ELRenameWindow.ShowGUI (this); } @@ -334,7 +336,7 @@ public double CalculateWork () public void OnRename () { - ELBuildWindow.updateCurrentPads (); + control.OnRename (oldName); } void OnCollisionStay (Collision collision) diff --git a/Source/Settings.cs b/Source/Settings.cs index ae443447..5415f494 100644 --- a/Source/Settings.cs +++ b/Source/Settings.cs @@ -202,9 +202,9 @@ void ParseShipInfo (ConfigNode settings) void ParseBuildWindow (ConfigNode settings) { - if (settings.HasNode ("BuildWindow")) { - var node = settings.GetNode ("BuildWindow"); - ELBuildWindow.LoadSettings (node); + if (settings.HasNode ("WindowManager")) { + var node = settings.GetNode ("WindowManager"); + ELWindowManager.LoadSettings (node); } } @@ -252,7 +252,7 @@ public override void OnSave(ConfigNode config) settings.AddValue ("DebugCraftHull", DebugCraftHull); ELShipInfo.SaveSettings (settings.AddNode ("ShipInfo")); - ELBuildWindow.SaveSettings (settings.AddNode ("BuildWindow")); + ELWindowManager.SaveSettings (settings.AddNode ("WindowManager")); ELResourceWindow.SaveSettings (settings.AddNode ("ResourceWindow")); } diff --git a/Source/Survey/SurveyStation.cs b/Source/Survey/SurveyStation.cs index 9f92c8a9..fc70025f 100644 --- a/Source/Survey/SurveyStation.cs +++ b/Source/Survey/SurveyStation.cs @@ -30,6 +30,7 @@ public class ELSurveyStation : PartModule, IModuleInfo, IPartMassModifier, ELBui { [KSPField (isPersistant = true, guiActive = true, guiName = "Pad name")] public string StationName = ""; + string oldName = ""; [KSPField (isPersistant = true)] public bool Operational = true; @@ -366,6 +367,7 @@ public override void OnStart (PartModule.StartState state) ELSurveyTracker.onSiteRemoved.Add (onSiteRemoved); ELSurveyTracker.onSiteModified.Add (onSiteModified); ELSurveyTracker.onStakeModified.Add (onStakeModified); + UpdateMenus (false); } void OnDestroy () @@ -384,20 +386,20 @@ void OnDestroy () [KSPEvent (guiActive = true, guiName = "Hide UI", active = false)] public void HideUI () { - ELBuildWindow.HideGUI (); + ELWindowManager.HideBuildWindow (); } [KSPEvent (guiActive = true, guiName = "Show UI", active = false)] public void ShowUI () { - ELBuildWindow.ShowGUI (); - ELBuildWindow.SelectPad (control); + ELWindowManager.ShowBuildWindow (control); } [KSPEvent (guiActive = true, guiActiveEditor = true, guiName = "Rename", active = true)] public void ShowRenameUI () { + oldName = StationName; ELRenameWindow.ShowGUI (this); } @@ -551,7 +553,7 @@ public double CalculateWork () public void OnRename () { - ELBuildWindow.updateCurrentPads (); + control.OnRename (oldName); } } } diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index ca269224..d770cf0a 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -78,5 +78,11 @@ public void SetVessel (Vessel vessel) statusBar.SetVessel (vessel); padView.SetVessel (vessel); } + + public void SetControl (ELBuildControl control) + { + statusBar.SetVessel (control.builder.vessel); + padView.SetControl (control); + } } } diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index b346c322..7afca520 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -66,11 +66,13 @@ private set { protected override void Awake () { ELBuildControl.onBuildStateChanged.Add (onBuildStateChanged); + ELBuildControl.onPadRenamed.Add (onPadRenamed); } protected override void OnDestroy () { ELBuildControl.onBuildStateChanged.Remove (onBuildStateChanged); + ELBuildControl.onPadRenamed.Remove (onPadRenamed); } void onBuildStateChanged (ELBuildControl control) @@ -80,6 +82,21 @@ void onBuildStateChanged (ELBuildControl control) } } + void onPadRenamed (ELBuildControl control, string oldName, string newName) + { + bool changed = false; + for (int i = padControls.Count; i-- > 0; ) { + if (padControls[i] == control) { + padNames[i].text = PadName (padControls[i].builder, i); + changed = true; + } + } + + if (changed) { + padSelector.Options (padNames); + } + } + public override void CreateUI() { base.CreateUI (); @@ -135,6 +152,19 @@ public override void Style () void SelectPad (int index) { control = padControls[index]; + worknet.selectedPad = control.builder.ID; + UpdateMenus (gameObject.activeInHierarchy); + } + + void UpdateMenus (bool visible) + { + if (padControls == null) { + return; + } + for (int i = padControls.Count; i-- > 0; ) { + bool selected = padControls[i] == control; + padControls[i].builder.UpdateMenus (visible && selected); + } } static ELVesselWorkNet FindWorkNet (Vessel v) @@ -160,12 +190,20 @@ static ELBuildControl FindControl (Vessel v, uint id) return null; } + string PadName (ELBuildControl.IBuilder pad, int index) + { + if (String.IsNullOrEmpty (pad.Name)) { + return $"{ELLocalization.Pad}-{index}"; + } else { + return pad.Name; + } + } + void BuildPadList () { padNames.Clear (); padControls.Clear (); worknet = null; - control = null; if (!vessel) { return; } @@ -177,29 +215,41 @@ void BuildPadList () padSelector.interactable = false; } else { worknet = FindWorkNet (vessel); - if (worknet != null) { + if (worknet != null && control == null) { control = FindControl (vessel, worknet.selectedPad); } for (int i = 0; i < pads.Count; i++) { - if (String.IsNullOrEmpty (pads[i].Name)) { - padNames.Add (new OptionData ($"{ELLocalization.Pad}-{i}")); - } else { - padNames.Add (new OptionData (pads[i].Name)); - } + padNames.Add (new OptionData (PadName (pads[i], i))); padControls.Add (pads[i].control); if (control == pads[i].control) { control_index = i; } } } + if (control == null) { + control_index = 0; + } + if (control_index < padControls.Count) { + control = padControls[control_index]; + } padSelector.Options (padNames); padSelector.SetValueWithoutNotify (control_index); + + UpdateMenus (gameObject.activeInHierarchy); } public void SetVessel (Vessel vessel) { this.vessel = vessel; + control = null; + BuildPadList (); + } + + public void SetControl (ELBuildControl control) + { + vessel = control.builder.vessel; + this.control = control; BuildPadList (); } @@ -213,12 +263,14 @@ protected override void OnEnable () { base.OnEnable (); GameEvents.onVesselWasModified.Add (onVesselWasModified); + UpdateMenus (gameObject.activeInHierarchy); } protected override void OnDisable () { base.OnDisable (); GameEvents.onVesselWasModified.Remove (onVesselWasModified); + UpdateMenus (false); } } } diff --git a/Source/UI/WindowManager.cs b/Source/UI/WindowManager.cs new file mode 100644 index 00000000..c108413d --- /dev/null +++ b/Source/UI/WindowManager.cs @@ -0,0 +1,133 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + [KSPAddon (KSPAddon.Startup.Flight, true)] + public class ELWindowManager : MonoBehaviour + { + static ELWindowManager instance; + + static bool gui_enabled = true; + static Rect windowpos; + + static double minimum_alarm_time = 60; + + static bool KACinited = false; + + internal void Start() + { + if (!KACinited) { + KACinited = true; + KACWrapper.InitKACWrapper(); + } + if (KACWrapper.APIReady) + { + //All good to go + Debug.Log ("KACWrapper initialized"); + } + } + + public static void LoadSettings (ConfigNode node) + { + string val = node.GetValue ("rect"); + if (val != null) { + Quaternion pos; + pos = ConfigNode.ParseQuaternion (val); + windowpos.x = pos.x; + windowpos.y = pos.y; + windowpos.width = pos.z; + windowpos.height = pos.w; + } + val = node.GetValue ("visible"); + if (val != null) { + bool.TryParse (val, out gui_enabled); + } + val = node.GetValue ("minimum_alarm_time"); + if (val != null) { + double.TryParse (val, out minimum_alarm_time); + } + } + + public static void SaveSettings (ConfigNode node) + { + } + + public static void HideBuildWindow () + { + if (mainWindow) { + mainWindow.gameObject.SetActive (false); + } + } + + public static void ShowBuildWindow (ELBuildControl control) + { + if (!mainWindow) { + mainWindow = UIKit.CreateUI (appCanvasRect, "ELMainWindow"); + } + mainWindow.gameObject.SetActive (true); + if (control != null) { + mainWindow.SetControl (control); + } else { + mainWindow.SetVessel (FlightGlobals.ActiveVessel); + } + } + + public static void ToggleBuildWindow () + { + if (!mainWindow || !mainWindow.gameObject.activeSelf) { + ShowBuildWindow (null); + } else { + HideBuildWindow (); + } + } + + static Canvas appCanvas; + static RectTransform appCanvasRect; + static ELMainWindow mainWindow; + + void Awake () + { + instance = this; + GameObject.DontDestroyOnLoad(this); + appCanvas = DialogCanvasUtil.DialogCanvas; + appCanvasRect = appCanvas.transform as RectTransform; + } + + void OnDestroy () + { + instance = null; + if (mainWindow) { + Destroy (mainWindow.gameObject); + mainWindow = null; + } + } + } +} diff --git a/Source/toolbar/Toolbar.cs b/Source/toolbar/Toolbar.cs index a3bc05b8..c4937e0a 100644 --- a/Source/toolbar/Toolbar.cs +++ b/Source/toolbar/Toolbar.cs @@ -117,7 +117,7 @@ public class ELToolbar_BuildWindow : MonoBehaviour public void Awake () { - ELAppButton.Toggle += ELBuildWindow.ToggleGUI; + ELAppButton.Toggle += ELWindowManager.ToggleBuildWindow; ELAppButton.RightToggle += ELResourceWindow.ToggleGUI; if (ToolbarManager.Instance == null) { @@ -127,7 +127,7 @@ public void Awake () ELBuildWindowButton.Visible = ELSettings.PreferBlizzy; ELBuildWindowButton.TexturePath = "ExtraplanetaryLaunchpads/Textures/icon_button"; ELBuildWindowButton.ToolTip = "EL Build Window"; - ELBuildWindowButton.OnClick += (e) => ELBuildWindow.ToggleGUI (); + ELBuildWindowButton.OnClick += (e) => ELWindowManager.ToggleBuildWindow (); } void OnDestroy() @@ -135,7 +135,7 @@ void OnDestroy() if (ELBuildWindowButton != null) { ELBuildWindowButton.Destroy (); } - ELAppButton.Toggle -= ELBuildWindow.ToggleGUI; + ELAppButton.Toggle -= ELWindowManager.ToggleBuildWindow; ELAppButton.RightToggle -= ELResourceWindow.ToggleGUI; } } From 02dfef32e81d7da9dc128f15adebab30ca73a5db Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 15:45:36 +0900 Subject: [PATCH 035/150] Get the resource font sizes to something reasonable Really need to get styles more complete, but it's nice to have the sizes working at all. --- KodeUI | 2 +- Source/UI/ResourceLine.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/KodeUI b/KodeUI index 637e78cb..d0604733 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 637e78cbbd56274829786c17f41b0bdba33b255d +Subproject commit d0604733d9f8af941a1ca071ce38249db1f5425f diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index d6de6f6b..abf2836e 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -72,14 +72,14 @@ public override void CreateUI() base.CreateUI (); Vector2 nameMin = new Vector2 (0, 0); - Vector2 nameMax = new Vector2 (0.175f, 1); - Vector2 fractionMin = new Vector2 (0.20f, 0); - Vector2 fractionMax = new Vector2 (0.65f, 1); - Vector2 amountsMin = new Vector2 (0.675f, 0); + Vector2 nameMax = new Vector2 (0.2f, 1); + Vector2 fractionMin = new Vector2 (0.2f, 0); + Vector2 fractionMax = new Vector2 (0.7f, 1); + Vector2 amountsMin = new Vector2 (0.7f, 0); Vector2 amountsMax = new Vector2 (1, 1); var requiredMin = new Vector2 (0, 0); - var requiredMax = new Vector2 (0.475f, 1); - var availableMin = new Vector2 (0.525f, 0); + var requiredMax = new Vector2 (0.48f, 1); + var availableMin = new Vector2 (0.52f, 0); var availableMax = new Vector2 (1, 1); var textMargins = new Vector4 (5, 5, 10, 10); @@ -101,6 +101,7 @@ public override void CreateUI() .Finish() .Add (out resourceName) .Text("resource") + .Size (15) .Margin (textMargins) .Alignment (TextAlignmentOptions.Left) .Anchor (AnchorPresets.StretchAll) @@ -118,6 +119,7 @@ public override void CreateUI() .SizeDelta (0, 0) .Finish () .Add (out info, "ResourceInfo") + .Size (15) .Margin (textMargins) .Alignment (TextAlignmentOptions.Center) .Anchor (AnchorPresets.StretchAll) @@ -139,7 +141,7 @@ public override void CreateUI() .Finish() .Add (out amount) .Text ("500") - .Size (12) + .Size (15) .Margin (textMargins) .Alignment (TextAlignmentOptions.Right) .Anchor (AnchorPresets.StretchAll) @@ -158,7 +160,7 @@ public override void CreateUI() .Finish () .Add (out available) .Text ("1000") - .Size (12) + .Size (15) .Margin (textMargins) .Alignment (TextAlignmentOptions.Right) .Anchor (AnchorPresets.StretchAll) From fd46cda544e73722ac9319eae97bed16317672fa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 15:57:38 +0900 Subject: [PATCH 036/150] Update resource line elements only when necessary --- Source/UI/ResourceLine.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index abf2836e..fb2ced8e 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -43,19 +43,28 @@ static string displayAmount (double amount) { } } + void UpdateText (UIText text, string str) + { + if (text.tmpText.text != str) { + text.Text (str); + } + } + public void UpdateDisplay() { if (resource.ResourceInfo != null) { info.Text(resource.ResourceInfo); } double frac = resource.ResourceFraction; - fraction.slider.SetValueWithoutNotify ((float) frac); + if (frac != fraction.slider.value) { + fraction.slider.SetValueWithoutNotify ((float) frac); + } double amount = resource.BuildAmount; double available = resource.AvailableAmount; if (available >= 0) { - this.available.Text (displayAmount (available)); + UpdateText (this.available, displayAmount (available)); } Color color = UnityEngine.Color.green; if (available >= 0 && available < amount) { @@ -64,7 +73,7 @@ public void UpdateDisplay() color = UnityEngine.Color.white; } this.amount.Color(color).Style(); - this.amount.Text (displayAmount (amount)); + UpdateText (this.amount, displayAmount (amount)); } public override void CreateUI() From 79a7072e0138d425948a45a1868ad8653c7e26de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 16:50:48 +0900 Subject: [PATCH 037/150] Save and restore the new build window's state --- Source/UI/MainWindow.cs | 5 +++ Source/UI/WindowManager.cs | 78 ++++++++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 19 deletions(-) diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index d770cf0a..9589a3c5 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -84,5 +84,10 @@ public void SetControl (ELBuildControl control) statusBar.SetVessel (control.builder.vessel); padView.SetControl (control); } + + public void SetVisible (bool visible) + { + gameObject.SetActive (visible); + } } } diff --git a/Source/UI/WindowManager.cs b/Source/UI/WindowManager.cs index c108413d..798efe36 100644 --- a/Source/UI/WindowManager.cs +++ b/Source/UI/WindowManager.cs @@ -35,13 +35,33 @@ public class ELWindowManager : MonoBehaviour { static ELWindowManager instance; - static bool gui_enabled = true; - static Rect windowpos; - static double minimum_alarm_time = 60; static bool KACinited = false; + struct WindowInfo { + public bool visible; + public Vector2 position; + + public void Load (ConfigNode node) + { + string val = node.GetValue ("position"); + if (val != null) { + ParseExtensions.TryParseVector2 (val, out position); + } + val = node.GetValue ("visible"); + if (val != null) { + bool.TryParse (val, out visible); + } + } + + public void Save (ConfigNode node) + { + node.AddValue ("position", position); + node.AddValue ("visible", visible); + } + } + internal void Start() { if (!KACinited) { @@ -57,42 +77,39 @@ internal void Start() public static void LoadSettings (ConfigNode node) { - string val = node.GetValue ("rect"); - if (val != null) { - Quaternion pos; - pos = ConfigNode.ParseQuaternion (val); - windowpos.x = pos.x; - windowpos.y = pos.y; - windowpos.width = pos.z; - windowpos.height = pos.w; - } - val = node.GetValue ("visible"); - if (val != null) { - bool.TryParse (val, out gui_enabled); - } - val = node.GetValue ("minimum_alarm_time"); + string val = node.GetValue ("minimum_alarm_time"); if (val != null) { double.TryParse (val, out minimum_alarm_time); } + if (node.HasNode ("MainWindow")) { + mainWindowInfo.Load (node.GetNode ("MainWindow")); + } } public static void SaveSettings (ConfigNode node) { + if (mainWindow) { + mainWindowInfo.position = mainWindow.transform.localPosition; + } + mainWindowInfo.Save (node.AddNode ("MainWindow")); } public static void HideBuildWindow () { if (mainWindow) { - mainWindow.gameObject.SetActive (false); + mainWindow.SetVisible (false); } + mainWindowInfo.visible = false; } public static void ShowBuildWindow (ELBuildControl control) { if (!mainWindow) { mainWindow = UIKit.CreateUI (appCanvasRect, "ELMainWindow"); + mainWindow.transform.position = mainWindowInfo.position; } - mainWindow.gameObject.SetActive (true); + mainWindowInfo.visible = true; + mainWindow.SetVisible (true); if (control != null) { mainWindow.SetControl (control); } else { @@ -111,6 +128,8 @@ public static void ToggleBuildWindow () static Canvas appCanvas; static RectTransform appCanvasRect; + + static WindowInfo mainWindowInfo = new WindowInfo (); static ELMainWindow mainWindow; void Awake () @@ -119,6 +138,9 @@ void Awake () GameObject.DontDestroyOnLoad(this); appCanvas = DialogCanvasUtil.DialogCanvas; appCanvasRect = appCanvas.transform as RectTransform; + + GameEvents.onGameSceneSwitchRequested.Add (onGameSceneSwitchRequested); + GameEvents.onLevelWasLoadedGUIReady.Add (onLevelWasLoadedGUIReady); } void OnDestroy () @@ -128,6 +150,24 @@ void OnDestroy () Destroy (mainWindow.gameObject); mainWindow = null; } + GameEvents.onGameSceneSwitchRequested.Remove (onGameSceneSwitchRequested); + GameEvents.onLevelWasLoadedGUIReady.Remove (onLevelWasLoadedGUIReady); + } + + void onGameSceneSwitchRequested(GameEvents.FromToAction data) + { + if (mainWindow) { + mainWindow.SetVisible (false); + } + } + + void onLevelWasLoadedGUIReady(GameScenes scene) + { + if (scene == GameScenes.FLIGHT) { + if (mainWindowInfo.visible) { + ShowBuildWindow (null); + } + } } } } From 792847fa03402b3c812f8bb19ad664094c26637a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 4 Oct 2020 21:24:49 +0900 Subject: [PATCH 038/150] Implement configurable linked resources Of course, the link can be "broken", but it makes tweaking post-build transfers a lot easier. Better yet, the links are configurable with unlimited resources in the set. However, overlaps between link sets will cause rhinodaemons. --- .../Resources/Recipes.cfg | 6 + Source/Recipes/RecipeDatabase.cs | 2 + Source/Recipes/RecipeLoader.cs | 20 ++ Source/Recipes/ResourceLink.cs | 85 +++++++ Source/UI/BuildView.cs | 10 +- Source/UI/CraftView.cs | 10 +- Source/UI/StatusBar.cs | 16 +- Source/UI/TransferView.cs | 211 +++++++++++++++++- 8 files changed, 342 insertions(+), 18 deletions(-) create mode 100644 Source/Recipes/ResourceLink.cs diff --git a/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg b/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg index ea49367c..d30240a8 100644 --- a/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Resources/Recipes.cfg @@ -177,6 +177,12 @@ EL_ConverterRecipe { } } +EL_ResourceLink { + name = RocketFuel + resource = LiquidFuel + resource = Oxidizer +} + EL_ConverterRecipe { name = MetalWorking Input { diff --git a/Source/Recipes/RecipeDatabase.cs b/Source/Recipes/RecipeDatabase.cs index 0a6330b6..bad76604 100644 --- a/Source/Recipes/RecipeDatabase.cs +++ b/Source/Recipes/RecipeDatabase.cs @@ -26,6 +26,7 @@ namespace ExtraplanetaryLaunchpads { [KSPAddon (KSPAddon.Startup.Instantly, false)] public class ELRecipeDatabase: MonoBehaviour { + public static Dictionary resource_links; public static Dictionary resource_rates; public static double default_resource_rate; public static Dictionary converter_recipes; @@ -142,6 +143,7 @@ public static void ProcessPart (Part part, Dictionary re void Awake () { + resource_links = new Dictionary (); resource_rates = new Dictionary (); // default to 5 kH/t (or per unit if 0 density) default_resource_rate = 5; diff --git a/Source/Recipes/RecipeLoader.cs b/Source/Recipes/RecipeLoader.cs index b5e5d025..e9adc003 100644 --- a/Source/Recipes/RecipeLoader.cs +++ b/Source/Recipes/RecipeLoader.cs @@ -65,6 +65,25 @@ ConfigNode GetResources (ConfigNode node, string recipe_name) return resources; } + IEnumerator LoadResourceLinks () + { + var dbase = GameDatabase.Instance; + var node_list = dbase.GetConfigNodes ("EL_ResourceLink"); + for (int i = 0; i < node_list.Length; i++) { + var node = node_list[i]; + string name = node.GetValue ("name"); + if (String.IsNullOrEmpty (name)) { + print ("[EL Recipes] skipping unnamed EL_ResourceLink"); + continue; + } + + var link = new ResourceLink (node); + //print ("[EL ResourceRecipe] " + name); + ELRecipeDatabase.resource_links[name] = link; + yield return null; + } + } + IEnumerator LoadResourceRates () { var dbase = GameDatabase.Instance; @@ -254,6 +273,7 @@ IEnumerator LoadRecipes() { LoadDefautStructureRecipe (); LoadKerbalRecipe (); + yield return StartCoroutine (LoadResourceLinks ()); yield return StartCoroutine (LoadResourceRates ()); yield return StartCoroutine (LoadResourceRecipes ()); yield return StartCoroutine (LoadRecycleRecipes ()); diff --git a/Source/Recipes/ResourceLink.cs b/Source/Recipes/ResourceLink.cs new file mode 100644 index 00000000..7bda8d9c --- /dev/null +++ b/Source/Recipes/ResourceLink.cs @@ -0,0 +1,85 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace ExtraplanetaryLaunchpads { + public class ResourceLink : ICollection + { + HashSet links; + + public int Count { get { return links.Count; } } + + public bool IsSynchronized { get { return false; } } + + public object SyncRoot { get { return this; } } + + public bool IsReadOnly { get { return false; } } + + public bool Contains (string res) + { + return links.Contains(res); + } + + public void CopyTo (string []array, int index) + { + foreach (var res in links) { + array.SetValue (res, index++); + } + } + + IEnumerator IEnumerable.GetEnumerator () + { + return links.GetEnumerator (); + } + + public IEnumerator GetEnumerator () + { + return links.GetEnumerator (); + } + + public ResourceLink (ConfigNode node) + { + links = new HashSet (); + for (int i = 0; i < node.values.Count; i++) { + var val = node.values[i]; + if (val.name == "resource") { + links.Add (val.value); + } + } + } + + public void Add (string res) + { + links.Add (res); + } + + public bool Remove (string res) + { + return links.Remove (res); + } + + public void Clear () + { + links.Clear (); + } + } +} diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index e502bedf..76bd0a69 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -58,7 +58,15 @@ public string ResourceInfo } } public double BuildAmount { get { return built.amount; } } - public double AvailableAmount { get { return available.amount; } } + public double AvailableAmount + { + get { + if (available == null) { + return 0; + } + return available.amount; + } + } public double ResourceFraction { get { diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index d2165836..7d052ddb 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -42,7 +42,15 @@ class RequiredResource : IResourceLine public string ResourceName { get { return required.name; } } public string ResourceInfo { get { return null; } } public double BuildAmount { get { return required.amount; } } - public double AvailableAmount { get { return available.amount; } } + public double AvailableAmount + { + get { + if (available == null) { + return 0; + } + return available.amount; + } + } public double ResourceFraction { get { diff --git a/Source/UI/StatusBar.cs b/Source/UI/StatusBar.cs index f5d47a17..a491db47 100644 --- a/Source/UI/StatusBar.cs +++ b/Source/UI/StatusBar.cs @@ -106,20 +106,22 @@ void UpdateSituation () void UpdateProductivity () { + string productivityStr = "----"; + Color c = UnityEngine.Color.red; //FIXME styles + if (worknet != null) { double p = worknet.Productivity; - Color c = UnityEngine.Color.green; //FIXME styles + c = UnityEngine.Color.green; //FIXME styles if (p <= 0) { c = UnityEngine.Color.red; //FIXME styles } else if (p < 1) { c = UnityEngine.Color.yellow; //FIXME styles } - productivityLabel.Color (c).Style(); - productivity.Text($"{p:G3}").Color (c).Style(); - } else { - Color c = UnityEngine.Color.red; //FIXME styles - productivityLabel.Color (c).Style(); - productivity.Text("----").Color (c).Style(); + productivityStr = $"{p:G3}"; + } + productivityLabel.Color (c).Style(); + if (productivity.tmpText.text != productivityStr) { + productivity.Text(productivityStr).Color (c).Style(); } } diff --git a/Source/UI/TransferView.cs b/Source/UI/TransferView.cs index d60202f7..ec065e0d 100644 --- a/Source/UI/TransferView.cs +++ b/Source/UI/TransferView.cs @@ -34,12 +34,13 @@ namespace ExtraplanetaryLaunchpads { public class ELTransferView : Layout { - public class TransferResource : IResourceLine, IResourceLineAdjust + class TransferResource : IResourceLine, IResourceLineAdjust { ELBuildControl control; BuildResource optional; RMResourceInfo capacity; RMResourceInfo available; + public LinkedResources link; public string ResourceName { get { return optional.name; } } public string ResourceInfo @@ -49,7 +50,15 @@ public string ResourceInfo } } public double BuildAmount { get { return optional.amount; } } - public double AvailableAmount { get { return available.amount; } } + public double AvailableAmount + { + get { + if (available == null) { + return 0; + } + return available.amount; + } + } public double ResourceFraction { get { @@ -57,9 +66,17 @@ public double ResourceFraction } set { optional.amount = value * capacity.maxAmount; + if (link != null) { + link.SetFraction (value); + } } } + public void SetFraction (double fraction) + { + optional.amount = fraction * capacity.maxAmount; + } + public TransferResource (BuildResource opt, RMResourceInfo cap, RMResourceInfo pad, ELBuildControl control) { optional = opt; @@ -69,23 +86,132 @@ public TransferResource (BuildResource opt, RMResourceInfo cap, RMResourceInfo p } } + class LinkedResources : LayoutAnchor + { + List resources; + bool linked; + + ELResourceDisplay display; + UIEmpty linkView; + UIToggle linkToggle; + + public void SetFraction (double value) + { + if (linked) { + for (int i = resources.Count; i-- > 0; ) { + (resources[i] as TransferResource).SetFraction (value); + } + } + } + + public override void CreateUI () + { + base.CreateUI (); + this.DoPreferredHeight (true) + .FlexibleLayout (true, false) + .Add (out display) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (-20, 0) + .Pivot (PivotPresets.TopLeft) + .Finish () + .Add (out linkView) + .Anchor (AnchorPresets.VertStretchRight) + .Pivot (PivotPresets.MiddleRight) + .SizeDelta (20, 0) + .Add ("LinkTop") + .Type (Image.Type.Sliced) + .FlexibleLayout (true, true) + .SizeDelta (0, 0) + .Finish () + .Add (out linkToggle, "LinkToggle") + .OnValueChanged (UpdateLinked) + .SetIsOnWithoutNotify (false) + .Anchor (AnchorPresets.MiddleRight) + .Pivot (PivotPresets.MiddleRight) + .SizeDelta (20, 20) + .Finish () + .Add ("LinkBottom") + .Type (Image.Type.Sliced) + .FlexibleLayout (true, true) + .SizeDelta (0, 0) + .Finish () + .Finish (); + linkView.gameObject.SetActive (false); + } + + void UpdateLinked (bool value) + { + linked = value; + } + + public LinkedResources UnLinked () + { + this.linked = false; + linkView.gameObject.SetActive (false); + return this; + } + + public LinkedResources Linked (bool linked) + { + this.linked = linked; + linkView.gameObject.SetActive (true); + linkToggle.SetIsOnWithoutNotify (linked); + return this; + } + + public LinkedResources Resources (List resources) + { + this.resources = resources; + for (int i = resources.Count; i-- > 0; ) { + (resources[i] as TransferResource).link = this; + } + display.Resources (resources); + return this; + } + } + + public class Link + { + public List link { get; } + public int Count { get { return link.Count; } } + public void Clear () { link.Clear (); } + public Link () + { + link = new List (); + } + } + UIButton releaseButton; ScrollView craftView; Layout selectedCraft; - ELResourceDisplay resourceList; UIText craftName; List transferResources; ELBuildControl control; + Dictionary linkMap; + List linkList; + public override void CreateUI() { if (transferResources == null) { transferResources = new List (); } + if (linkMap == null) { + linkMap = new Dictionary (); + linkList = new List (); + foreach (var resLink in ELRecipeDatabase.resource_links.Values) { + var link = new Link (); + linkList.Add (link); + foreach (var res in resLink) { + linkMap[res] = link; + } + } + } + base.CreateUI (); var leftMin = new Vector2 (0, 0); @@ -150,8 +276,6 @@ public override void CreateUI() .Anchor (AnchorPresets.HorStretchTop) .PreferredSizeFitter(true, false) .WidthDelta(0) - .Add (out resourceList) - .Finish () .Finish (); } @@ -180,14 +304,83 @@ static BuildResource FindResource (List reslist, string name) void RebuildResources () { + for (int i = linkList.Count; i-- > 0; ) { + linkList[i].Clear(); + } transferResources.Clear (); foreach (var res in control.buildCost.optional) { var opt = control.craftResources[res.name]; - var available = control.padResources[res.name]; - var line = new TransferResource (res, opt, available, control); - transferResources.Add (line); + var avail = control.padResources[res.name]; + var link = transferResources; + TransferResource tres; + if (linkMap.ContainsKey (res.name)) { + link = linkMap[res.name].link; + tres = new TransferResource (res, opt, avail, control); + } else { + tres = new TransferResource (res, opt, avail, control); + } + Debug.Log ($"[ELTransferView] RebuildResources {res.name} {opt} {avail} {link}"); + link.Add (tres); + } + + int itemCount = 0; + for (int i = linkList.Count; i-- > 0; ) { + if(linkList[i].Count > 0) { + ++itemCount; + } + } + + var contentRect = craftView.Content.rectTransform; + int childCount = contentRect.childCount; + int childIndex = 0; + int itemIndex = 0; + if (transferResources.Count > 0) { + if (childIndex < childCount) { + var child = contentRect.GetChild (childIndex); + var item = child.GetComponent (); + item.Resources (transferResources) + .UnLinked (); + ++childIndex; + } else { + craftView.Content + .Add () + .Resources (transferResources) + .UnLinked () + .FlexibleLayout(true, false) + .SizeDelta (0, 0) + .Finish (); + } + } + while (childIndex < childCount && itemIndex < itemCount) { + while (linkList[itemIndex].Count < 1) { + ++itemIndex; + ++itemCount; + } + var child = contentRect.GetChild (childIndex); + var item = child.GetComponent (); + item.Resources (linkList[itemIndex].link) + .Linked (true); // FIXME save linked state + ++childIndex; + ++itemIndex; + } + while (childIndex < childCount) { + var go = contentRect.GetChild (childIndex++).gameObject; + Destroy (go); + } + while (itemIndex < itemCount) { + while (linkList[itemIndex].Count < 1) { + ++itemIndex; + ++itemCount; + } + craftView.Content + .Add () + .Resources (linkList[itemIndex].link) + .Linked (true) // FIXME save linked state + .FlexibleLayout(true, false) + .SizeDelta (0, 0) + .Finish (); + ++itemIndex; } - resourceList.Resources (transferResources); } IEnumerator WaitAndRebuildResources () From 63c0dee1f0ae66d4067900e79ff4e2aafb4647b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 5 Oct 2020 09:46:10 +0900 Subject: [PATCH 039/150] Convert ShipInfo to the new UI --- KodeUI | 2 +- Source/GUI/ShipInfo.cs | 253 ------------------------------------ Source/Makefile | 4 +- Source/Settings.cs | 20 +-- Source/UI/Localization.cs | 5 + Source/UI/ShipInfo.cs | 106 +++++++++++++++ Source/UI/ShipInfoWindow.cs | 205 +++++++++++++++++++++++++++++ Source/UI/TextInfoLine.cs | 87 +++++++++++++ Source/UI/WindowManager.cs | 49 ++++++- Source/toolbar/Toolbar.cs | 6 +- 10 files changed, 463 insertions(+), 274 deletions(-) delete mode 100644 Source/GUI/ShipInfo.cs create mode 100644 Source/UI/ShipInfo.cs create mode 100644 Source/UI/ShipInfoWindow.cs create mode 100644 Source/UI/TextInfoLine.cs diff --git a/KodeUI b/KodeUI index d0604733..70990cca 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit d0604733d9f8af941a1ca071ce38249db1f5425f +Subproject commit 70990ccab576554e5296737bcd55c39f6981fd76 diff --git a/Source/GUI/ShipInfo.cs b/Source/GUI/ShipInfo.cs deleted file mode 100644 index 893453c0..00000000 --- a/Source/GUI/ShipInfo.cs +++ /dev/null @@ -1,253 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KSP.UI.Screens; - -namespace ExtraplanetaryLaunchpads { - [KSPAddon (KSPAddon.Startup.EditorAny, false)] - public class ELShipInfo : MonoBehaviour - { - static Rect winpos; - public static bool showGUI = false; - - int parts_count; - public BuildCost buildCost; - CostReport cashed_cost; - ELScrollView reqScroll = new ELScrollView (100); - ELScrollView optScroll = new ELScrollView (100); - - public static void ToggleGUI () - { - showGUI = !showGUI; - if (!showGUI) { - InputLockManager.RemoveControlLock ("EL_ShipInfo_window_lock"); - } - } - - public static void LoadSettings (ConfigNode node) - { - string val = node.GetValue ("rect"); - if (val != null) { - Quaternion pos; - pos = ConfigNode.ParseQuaternion (val); - winpos.x = pos.x; - winpos.y = pos.y; - winpos.width = pos.z; - winpos.height = pos.w; - } - val = node.GetValue ("visible"); - if (val != null) { - bool.TryParse (val, out showGUI); - } - } - - public static void SaveSettings (ConfigNode node) - { - Quaternion pos; - pos.x = winpos.x; - pos.y = winpos.y; - pos.z = winpos.width; - pos.w = winpos.height; - node.AddValue ("rect", KSPUtil.WriteQuaternion (pos)); - node.AddValue ("visible", showGUI); - } - - void addPart (Part part) - { - //Debug.Log (String.Format ("[EL GUI] attach: {0}", part)); - buildCost.addPart (part); - parts_count++; - } - - int rebuild_list_wait_frames = 0; - - private IEnumerator WaitAndRebuildList () - { - while (--rebuild_list_wait_frames > 0) { - yield return null; - } - ShipConstruct ship = EditorLogic.fetch.ship; - //Debug.LogFormat ("ELShipInfo.WaitAndRebuildList: {0}", ship); - - buildCost = null; - cashed_cost = null; - parts_count = 0; - - if (ship == null || ship.parts == null || ship.parts.Count < 1 - || ship.parts[0] == null) { - yield break; - } - - if (ship.parts.Count > 0) { - Part root = ship.parts[0].localRoot; - - buildCost = new BuildCost (); - addPart (root); - foreach (Part p in root.GetComponentsInChildren()) { - if (p != root) { - addPart (p); - } - } - } - cashed_cost = buildCost.cost; - } - - public void RebuildList() - { - // some parts/modules fire the event before doing things - const int wait_frames = 2; - if (rebuild_list_wait_frames < wait_frames) { - rebuild_list_wait_frames += wait_frames; - if (rebuild_list_wait_frames == wait_frames) { - StartCoroutine (WaitAndRebuildList ()); - } - } - } - - void onEditorShipModified (ShipConstruct ship) - { - RebuildList (); - } - - void onEditorRestart () - { - buildCost = null; - cashed_cost = null; - parts_count = 0; - } - - private void onEditorLoad (ShipConstruct ship, CraftBrowserDialog.LoadType loadType) - { - Debug.LogFormat ("ELShipInfo.onEditorLoad: {0} {1}", ship, loadType); - RebuildList (); - } - - void Awake () - { - GameEvents.onEditorShipModified.Add (onEditorShipModified); - GameEvents.onEditorRestart.Add (onEditorRestart); - GameEvents.onEditorLoad.Add (onEditorLoad); - } - - void OnDestroy () - { - GameEvents.onEditorShipModified.Remove (onEditorShipModified); - GameEvents.onEditorRestart.Remove (onEditorRestart); - GameEvents.onEditorLoad.Remove (onEditorLoad); - } - - void OnGUI () - { - if (!showGUI || buildCost == null) - return; - - if (winpos.x == 0 && winpos.y == 0) { - winpos.x = Screen.width / 2; - winpos.y = Screen.height / 2; - winpos.width = 300; - winpos.height = 100; - } - winpos = GUILayout.Window (GetInstanceID (), winpos, InfoWindow, - "Build Resources", - GUILayout.MinWidth (200)); - if (enabled && winpos.Contains (new Vector2 (Input.mousePosition.x, Screen.height - Input.mousePosition.y))) { - InputLockManager.SetControlLock ("EL_ShipInfo_window_lock"); - } else { - InputLockManager.RemoveControlLock ("EL_ShipInfo_window_lock"); - } - } - - private void UnitLabel (string title, double amount, string units) - { - GUILayout.BeginHorizontal (); - GUILayout.Label (title + ":"); - GUILayout.FlexibleSpace (); - GUILayout.Label (amount.ToStringSI(4, unit:units)); - GUILayout.EndHorizontal (); - } - - private void MassLabel (string title, double mass) - { - GUILayout.BeginHorizontal(); - GUILayout.Label(title + ":"); - GUILayout.FlexibleSpace(); - GUILayout.Label(EL_Utils.FormatMass(mass)); - GUILayout.EndHorizontal(); - } - - private void ResourcePanel (string title, - List resources, - ELScrollView scroll) - { - GUILayout.Label (title + ":"); - GUILayout.BeginVertical (GUILayout.Height (100)); - scroll.Begin (); - foreach (var res in resources) { - GUILayout.BeginHorizontal (); - GUILayout.Label (String.Format ("{0}:", res.name)); - GUILayout.FlexibleSpace (); - GUILayout.Label (String.Format ("{0} ({1})", res.amount.ToStringSI(4, unit:"u"), EL_Utils.FormatMass(res.mass, 4))); - GUILayout.EndHorizontal (); - } - scroll.End (); - GUILayout.EndVertical (); - } - - void InfoWindow (int windowID) - { - ELStyles.Init (); - - var cost = cashed_cost; - double required_mass = 0; - double resource_mass = 0; - double kerbalHours = 0; - - foreach (var res in cost.required) { - kerbalHours += res.kerbalHours * res.amount; - required_mass += res.mass; - } - kerbalHours = Math.Round (kerbalHours, 4); - - foreach (var res in cost.optional) { - resource_mass += res.mass; - } - - GUILayout.BeginVertical (); - - MassLabel ("Dry mass", buildCost.mass); - MassLabel ("Resource mass", resource_mass); - MassLabel ("Total mass", required_mass + resource_mass); - UnitLabel ("Build Time", kerbalHours, "Kh"); - - cost.optional.Sort (); - GUILayout.Label (" "); - ResourcePanel ("Required", cost.required, reqScroll); - ResourcePanel ("Optional", cost.optional, optScroll); - - string ver = ELVersionReport.GetVersion (); - GUILayout.Label(ver); - GUILayout.EndVertical (); - GUI.DragWindow (); - } - } -} diff --git a/Source/Makefile b/Source/Makefile index c5abffb4..0cb8ac3f 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -66,7 +66,6 @@ EL_FILES := \ GUI/RenameWindow.cs \ GUI/ResourceWindow.cs \ GUI/ScrollView.cs \ - GUI/ShipInfo.cs \ GUI/Styles.cs \ GUI/TextField.cs \ LaunchClamp/LaunchClamp.cs \ @@ -82,7 +81,10 @@ EL_FILES := \ UI/PadView.cs \ UI/ResourceDisplay.cs \ UI/ResourceLine.cs \ + UI/ShipInfo.cs \ + UI/ShipInfoWindow.cs \ UI/StatusBar.cs \ + UI/TextInfoLine.cs \ UI/TransferView.cs \ UI/WindowManager.cs \ Workshop/ConstructionSkill.cs \ diff --git a/Source/Settings.cs b/Source/Settings.cs index 5415f494..0c1bc4b4 100644 --- a/Source/Settings.cs +++ b/Source/Settings.cs @@ -192,15 +192,7 @@ void ParseDebugCraftHull (ConfigNode settings) UpdateToolbarButton (); } - void ParseShipInfo (ConfigNode settings) - { - if (settings.HasNode ("ShipInfo")) { - var node = settings.GetNode ("ShipInfo"); - ELShipInfo.LoadSettings (node); - } - } - - void ParseBuildWindow (ConfigNode settings) + void ParseWindowManager (ConfigNode settings) { if (settings.HasNode ("WindowManager")) { var node = settings.GetNode ("WindowManager"); @@ -230,8 +222,7 @@ public override void OnLoad (ConfigNode config) ParsePreferBlizzy (settings); ParseShowCraftHull (settings); ParseDebugCraftHull (settings); - ParseShipInfo (settings); - ParseBuildWindow (settings); + ParseWindowManager (settings); ParseResourceWindow (settings); if (HighLogic.LoadedScene == GameScenes.SPACECENTER) { @@ -251,7 +242,6 @@ public override void OnSave(ConfigNode config) settings.AddValue ("ShowCraftHull", ShowCraftHull); settings.AddValue ("DebugCraftHull", DebugCraftHull); - ELShipInfo.SaveSettings (settings.AddNode ("ShipInfo")); ELWindowManager.SaveSettings (settings.AddNode ("WindowManager")); ELResourceWindow.SaveSettings (settings.AddNode ("ResourceWindow")); } @@ -308,9 +298,9 @@ void WindowGUI (int windowID) uk = GUILayout.Toggle (uk, "Create alarms in Kerbal Alarm Clock"); use_KAC = uk; - bool si = ELShipInfo.showGUI; - si = GUILayout.Toggle (si, "Build Resources window currently visible in editor"); - ELShipInfo.showGUI = si; + //bool si = ELShipInfo.showGUI; + //si = GUILayout.Toggle (si, "Build Resources window currently visible in editor"); + //ELShipInfo.showGUI = si; bool sch = ShowCraftHull; sch = GUILayout.Toggle (sch, "Show craft hull during construction"); diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 12572963..6c74ce00 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -47,5 +47,10 @@ public static class ELLocalization public static string RestartBuild { get; } = "Restart Build"; public static string Paused { get; } = "[paused]"; public static string Release { get; } = "Release"; + public static string DryMass { get; } = "Dry mass"; + public static string ResourceMass { get; } = "Resource mass"; + public static string TotalMass { get; } = "Total mass"; + public static string BuildTime { get; } = "Build time"; + public static string KerbalHours { get; } = "Kh"; } } diff --git a/Source/UI/ShipInfo.cs b/Source/UI/ShipInfo.cs new file mode 100644 index 00000000..86e87b84 --- /dev/null +++ b/Source/UI/ShipInfo.cs @@ -0,0 +1,106 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + [KSPAddon (KSPAddon.Startup.EditorAny, true)] + public class ELShipInfo : MonoBehaviour + { + public static ELShipInfoWindow shipInfoWindow { get; set; } + + int rebuild_list_wait_frames = 0; + + private IEnumerator WaitAndRebuildList () + { + while (--rebuild_list_wait_frames > 0) { + yield return null; + } + ShipConstruct ship = EditorLogic.fetch.ship; + //Debug.LogFormat ("ELShipInfo.WaitAndRebuildList: {0}", ship); + + BuildCost buildCost = null; + + if (ship == null || ship.parts == null || ship.parts.Count < 1 + || ship.parts[0] == null) { + yield break; + } + + if (ship.parts.Count > 0) { + Part root = ship.parts[0].localRoot; + + buildCost = new BuildCost (); + buildCost.addPart (root); + foreach (Part p in root.GetComponentsInChildren()) { + if (p != root) { + buildCost.addPart (p); + } + } + } + if (shipInfoWindow) { + shipInfoWindow.UpdateInfo (buildCost); + } + } + + void RebuildList() + { + // some parts/modules fire the event before doing things + const int wait_frames = 2; + if (rebuild_list_wait_frames < wait_frames) { + rebuild_list_wait_frames += wait_frames; + if (rebuild_list_wait_frames == wait_frames) { + StartCoroutine (WaitAndRebuildList ()); + } + } + } + + void onEditorShipModified (ShipConstruct ship) + { + RebuildList (); + } + + void onEditorRestart () + { + } + + private void onEditorLoad (ShipConstruct ship, CraftBrowserDialog.LoadType loadType) + { + Debug.LogFormat ("ELShipInfo.onEditorLoad: {0} {1}", ship, loadType); + RebuildList (); + } + + void Awake () + { + GameEvents.onEditorShipModified.Add (onEditorShipModified); + GameEvents.onEditorRestart.Add (onEditorRestart); + GameEvents.onEditorLoad.Add (onEditorLoad); + } + + void OnDestroy () + { + GameEvents.onEditorShipModified.Remove (onEditorShipModified); + GameEvents.onEditorRestart.Remove (onEditorRestart); + GameEvents.onEditorLoad.Remove (onEditorLoad); + } + } +} diff --git a/Source/UI/ShipInfoWindow.cs b/Source/UI/ShipInfoWindow.cs new file mode 100644 index 00000000..9a7a1515 --- /dev/null +++ b/Source/UI/ShipInfoWindow.cs @@ -0,0 +1,205 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELShipInfoWindow : Window + { + ELTextInfoLine dryMass; + ELTextInfoLine resourceMass; + ELTextInfoLine totalMass; + ELTextInfoLine buildTime; + + ScrollView requiredResources; + ScrollView optionalResources; + + public override void CreateUI() + { + base.CreateUI (); + + UIScrollbar reqScrollbar; + UIScrollbar optScrollbar; + + this.Title (ELVersionReport.GetVersion ()) + .Vertical() + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .PreferredSizeFitter(true, true) + .Anchor(AnchorPresets.MiddleCenter) + .Pivot(PivotPresets.TopLeft) + .PreferredWidth(400) + + .Add (out dryMass) + .Label (ELLocalization.DryMass) + .Finish () + .Add (out resourceMass) + .Label (ELLocalization.ResourceMass) + .Finish () + .Add (out totalMass) + .Label (ELLocalization.TotalMass) + .Finish () + .Add (out buildTime) + .Label (ELLocalization.BuildTime) + .Finish () + + .Add (out requiredResources) + .Horizontal (false) + .Vertical (true) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout(true, false) + .PreferredHeight (120) + .Add (out reqScrollbar, "Scrollbar") + .Direction (Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Add (out optionalResources) + .Horizontal (false) + .Vertical (true) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout(true, false) + .PreferredHeight (120) + .Add (out optScrollbar, "Scrollbar") + .Direction (Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish (); + + requiredResources.VerticalScrollbar = reqScrollbar; + requiredResources.Viewport.FlexibleLayout (true, true); + requiredResources.Content + .Vertical() + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .Finish (); + + optionalResources.VerticalScrollbar = optScrollbar; + optionalResources.Viewport.FlexibleLayout (true, true); + optionalResources.Content + .Vertical() + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .Finish (); + } + + public override void Style () + { + base.Style (); + } + + public void SetVisible (bool visible) + { + gameObject.SetActive (visible); + ELShipInfo.shipInfoWindow = visible ? this : null; + } + + void SetMass (ELTextInfoLine info, double mass) + { + info.Info (EL_Utils.FormatMass (mass)); + } + + void SetUnit (ELTextInfoLine info, double amount, string units) + { + info.Info (amount.ToStringSI (4, unit:units)); + } + + void SetResource (ELTextInfoLine info, BuildResource res) + { + Debug.Log ($"[ELShipInfoWindow] SetResource {info} {res}"); + info.Label (res.name); + string amount = res.amount.ToStringSI (4, unit:"u"); + string mass = EL_Utils.FormatMass (res.mass, 4); + info.Info ($"{amount} {mass}"); + } + + void ResourceList (Layout content, List resources) + { + var contentRect = content.rectTransform; + int childCount = contentRect.childCount; + int childIndex = 0; + int itemIndex = 0; + int itemCount = resources.Count; + ELTextInfoLine item; + + while (childIndex < childCount && itemIndex < itemCount) { + var child = contentRect.GetChild (childIndex); + item = child.GetComponent (); + SetResource (item, resources[itemIndex]); + ++childIndex; + ++itemIndex; + } + while (childIndex < childCount) { + var go = contentRect.GetChild (childIndex++).gameObject; + Destroy (go); + } + while (itemIndex < itemCount) { + content.Add (out item) + .FlexibleLayout(true, false) + .SizeDelta (0, 0) + .Finish(); + SetResource (item, resources[itemIndex]); + ++itemIndex; + } + } + + public void UpdateInfo (BuildCost buildCost) + { + var cost = buildCost.cost; + double required_mass = 0; + double resource_mass = 0; + double kerbalHours = 0; + + foreach (var res in cost.required) { + kerbalHours += res.kerbalHours * res.amount; + required_mass += res.mass; + } + kerbalHours = Math.Round (kerbalHours, 4); + + foreach (var res in cost.optional) { + resource_mass += res.mass; + } + + SetMass (dryMass, buildCost.mass); + SetMass (resourceMass, resource_mass); + SetMass (totalMass, required_mass + resource_mass); + SetUnit (buildTime, kerbalHours, ELLocalization.KerbalHours); + + ResourceList (requiredResources.Content, cost.required); + ResourceList (optionalResources.Content, cost.optional); + } + } +} diff --git a/Source/UI/TextInfoLine.cs b/Source/UI/TextInfoLine.cs new file mode 100644 index 00000000..f07406fd --- /dev/null +++ b/Source/UI/TextInfoLine.cs @@ -0,0 +1,87 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELTextInfoLine : Layout + { + UIText label; + UIImage spacer; + UIText info; + + public override void CreateUI() + { + base.CreateUI (); + + var textMargins = new Vector4 (5, 5, 2, 2); + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.TopLeft) + .Pivot (PivotPresets.TopLeft) + .SizeDelta (0, 0) + .FlexibleLayout (true, false) + + .Add (out label, "InfoLabel") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Left) + .Anchor (AnchorPresets.TopLeft) + .SizeDelta (0, 0) + .FlexibleLayout (true, false) + .Finish () + .Add (out spacer, "InfoSpacer") + .Type (Image.Type.Sliced) + .Anchor (AnchorPresets.TopLeft) + .SizeDelta (0, 0) + .Finish () + .Add (out info, "InfoLabel") + .Margin (textMargins) + .Alignment (TextAlignmentOptions.Right) + .Anchor (AnchorPresets.TopLeft) + .SizeDelta (0, 0) + .FlexibleLayout (true, false) + .Finish () + ; + } + + public override void Style () + { + base.Style (); + } + + public ELTextInfoLine Label (string text) + { + label.Text (text + ":"); + return this; + } + + public ELTextInfoLine Info (string text) + { + info.Text (text); + return this; + } + } +} diff --git a/Source/UI/WindowManager.cs b/Source/UI/WindowManager.cs index 798efe36..2e263c62 100644 --- a/Source/UI/WindowManager.cs +++ b/Source/UI/WindowManager.cs @@ -30,7 +30,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - [KSPAddon (KSPAddon.Startup.Flight, true)] + [KSPAddon (KSPAddon.Startup.MainMenu, true)] public class ELWindowManager : MonoBehaviour { static ELWindowManager instance; @@ -92,6 +92,11 @@ public static void SaveSettings (ConfigNode node) mainWindowInfo.position = mainWindow.transform.localPosition; } mainWindowInfo.Save (node.AddNode ("MainWindow")); + + if (shipInfo) { + shipInfoInfo.position = shipInfo.transform.localPosition; + } + shipInfoInfo.Save (node.AddNode ("ShipInfo")); } public static void HideBuildWindow () @@ -126,12 +131,42 @@ public static void ToggleBuildWindow () } } + public static void HideShipInfo () + { + if (shipInfo) { + shipInfo.SetVisible (false); + } + shipInfoInfo.visible = false; + } + + public static void ShowShipInfo (ELBuildControl control) + { + if (!shipInfo) { + shipInfo = UIKit.CreateUI (appCanvasRect, "ELShipInfo"); + shipInfo.transform.position = shipInfoInfo.position; + } + shipInfoInfo.visible = true; + shipInfo.SetVisible (true); + } + + public static void ToggleShipInfo () + { + if (!shipInfo || !shipInfo.gameObject.activeSelf) { + ShowShipInfo (null); + } else { + HideShipInfo (); + } + } + static Canvas appCanvas; static RectTransform appCanvasRect; static WindowInfo mainWindowInfo = new WindowInfo (); static ELMainWindow mainWindow; + static WindowInfo shipInfoInfo = new WindowInfo (); + static ELShipInfoWindow shipInfo; + void Awake () { instance = this; @@ -150,6 +185,10 @@ void OnDestroy () Destroy (mainWindow.gameObject); mainWindow = null; } + if (shipInfo) { + Destroy (shipInfo.gameObject); + shipInfo = null; + } GameEvents.onGameSceneSwitchRequested.Remove (onGameSceneSwitchRequested); GameEvents.onLevelWasLoadedGUIReady.Remove (onLevelWasLoadedGUIReady); } @@ -159,6 +198,9 @@ void onGameSceneSwitchRequested(GameEvents.FromToAction if (mainWindow) { mainWindow.SetVisible (false); } + if (shipInfo) { + shipInfo.SetVisible (false); + } } void onLevelWasLoadedGUIReady(GameScenes scene) @@ -168,6 +210,11 @@ void onLevelWasLoadedGUIReady(GameScenes scene) ShowBuildWindow (null); } } + if (scene == GameScenes.EDITOR) { + if (shipInfoInfo.visible) { + ShowShipInfo (null); + } + } } } } diff --git a/Source/toolbar/Toolbar.cs b/Source/toolbar/Toolbar.cs index c4937e0a..c795d6fb 100644 --- a/Source/toolbar/Toolbar.cs +++ b/Source/toolbar/Toolbar.cs @@ -89,7 +89,7 @@ public class ELToolbar_ShipInfo : MonoBehaviour public void Awake () { - ELAppButton.Toggle += ELShipInfo.ToggleGUI; + ELAppButton.Toggle += ELWindowManager.ToggleShipInfo; if (ToolbarManager.Instance == null) { return; @@ -98,7 +98,7 @@ public void Awake () ELEditorButton.Visible = ELSettings.PreferBlizzy; ELEditorButton.TexturePath = "ExtraplanetaryLaunchpads/Textures/icon_button"; ELEditorButton.ToolTip = "EL Build Resources Display"; - ELEditorButton.OnClick += (e) => ELShipInfo.ToggleGUI (); + ELEditorButton.OnClick += (e) => ELWindowManager.ToggleShipInfo (); } void OnDestroy() @@ -106,7 +106,7 @@ void OnDestroy() if (ELEditorButton != null) { ELEditorButton.Destroy (); } - ELAppButton.Toggle -= ELShipInfo.ToggleGUI; + ELAppButton.Toggle -= ELWindowManager.ToggleShipInfo; } } From d57c9fe367661f087d00b63ba132244b65f56be0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 5 Oct 2020 09:46:54 +0900 Subject: [PATCH 040/150] Remove the forced colored backgrounds They were for debugging layout issues. --- Source/UI/PadView.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 7afca520..d3209a7f 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -119,7 +119,6 @@ public override void CreateUI() .Anchor (leftMin, leftMax) .SizeDelta (0, 0) .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) - .Color(UnityEngine.Color.blue) .Add (out padSelector, "PadSelector") .OnValueChanged (SelectPad) .FlexibleLayout (true, true) @@ -136,7 +135,6 @@ public override void CreateUI() .Anchor (rightMin, rightMax) .SizeDelta (0, 0) .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) - .Color(UnityEngine.Color.red) // XXX pad / survey controls .Finish () .Finish (); From 47677f8ab037edf708528d20a0f042c06471eaae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 5 Oct 2020 10:04:10 +0900 Subject: [PATCH 041/150] Rebuild cost when ship info window is shown --- Source/UI/ShipInfo.cs | 35 +++++++++++++++++++++++++++++------ Source/UI/ShipInfoWindow.cs | 2 +- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Source/UI/ShipInfo.cs b/Source/UI/ShipInfo.cs index 86e87b84..6d7e2dbf 100644 --- a/Source/UI/ShipInfo.cs +++ b/Source/UI/ShipInfo.cs @@ -24,26 +24,47 @@ You should have received a copy of the GNU General Public License using KSP.UI.Screens; namespace ExtraplanetaryLaunchpads { - [KSPAddon (KSPAddon.Startup.EditorAny, true)] + [KSPAddon (KSPAddon.Startup.EditorAny, false)] public class ELShipInfo : MonoBehaviour { - public static ELShipInfoWindow shipInfoWindow { get; set; } + static ELShipInfo instance; + + static ELShipInfoWindow _shipInfoWindow; + public static ELShipInfoWindow shipInfoWindow + { + get { return _shipInfoWindow; } + set { + _shipInfoWindow = value; + if (instance && _shipInfoWindow) { + instance.RebuildCost (); + } + } + } int rebuild_list_wait_frames = 0; - private IEnumerator WaitAndRebuildList () + private IEnumerator WaitAndRebuildCost () { while (--rebuild_list_wait_frames > 0) { yield return null; } + RebuildCost (); + } + + void RebuildCost () + { ShipConstruct ship = EditorLogic.fetch.ship; - //Debug.LogFormat ("ELShipInfo.WaitAndRebuildList: {0}", ship); + //Debug.LogFormat ("ELShipInfo.WaitAndRebuildCost: {0}", ship); BuildCost buildCost = null; if (ship == null || ship.parts == null || ship.parts.Count < 1 || ship.parts[0] == null) { - yield break; + if (shipInfoWindow) { + buildCost = new BuildCost (); + shipInfoWindow.UpdateInfo (buildCost); + } + return; } if (ship.parts.Count > 0) { @@ -69,7 +90,7 @@ void RebuildList() if (rebuild_list_wait_frames < wait_frames) { rebuild_list_wait_frames += wait_frames; if (rebuild_list_wait_frames == wait_frames) { - StartCoroutine (WaitAndRebuildList ()); + StartCoroutine (WaitAndRebuildCost ()); } } } @@ -91,6 +112,7 @@ private void onEditorLoad (ShipConstruct ship, CraftBrowserDialog.LoadType loadT void Awake () { + instance = this; GameEvents.onEditorShipModified.Add (onEditorShipModified); GameEvents.onEditorRestart.Add (onEditorRestart); GameEvents.onEditorLoad.Add (onEditorLoad); @@ -98,6 +120,7 @@ void Awake () void OnDestroy () { + instance = null; GameEvents.onEditorShipModified.Remove (onEditorShipModified); GameEvents.onEditorRestart.Remove (onEditorRestart); GameEvents.onEditorLoad.Remove (onEditorLoad); diff --git a/Source/UI/ShipInfoWindow.cs b/Source/UI/ShipInfoWindow.cs index 9a7a1515..61f263bf 100644 --- a/Source/UI/ShipInfoWindow.cs +++ b/Source/UI/ShipInfoWindow.cs @@ -50,7 +50,7 @@ public override void CreateUI() .PreferredSizeFitter(true, true) .Anchor(AnchorPresets.MiddleCenter) .Pivot(PivotPresets.TopLeft) - .PreferredWidth(400) + .PreferredWidth(350) .Add (out dryMass) .Label (ELLocalization.DryMass) From ac57783a9f8c8b49ab5cc2861be3961bc07eb60c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 5 Oct 2020 19:23:43 +0900 Subject: [PATCH 042/150] Reimplement the rename window in the new UI --- KodeUI | 2 +- Source/DisposablePad/DisposablePad.cs | 4 +- Source/GUI/RenameWindow.cs | 145 -------------------- Source/Makefile | 2 +- Source/Pad/Launchpad.cs | 4 +- Source/Survey/SurveySite.cs | 2 +- Source/Survey/SurveyStation.cs | 6 +- Source/UI/Localization.cs | 7 + Source/UI/RenameDialog.cs | 188 ++++++++++++++++++++++++++ Source/UI/WindowManager.cs | 2 +- 10 files changed, 206 insertions(+), 156 deletions(-) delete mode 100644 Source/GUI/RenameWindow.cs create mode 100644 Source/UI/RenameDialog.cs diff --git a/KodeUI b/KodeUI index 70990cca..8de02f71 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 70990ccab576554e5296737bcd55c39f6981fd76 +Subproject commit 8de02f718d45deba197dbd2a2cff9d140c42eb5a diff --git a/Source/DisposablePad/DisposablePad.cs b/Source/DisposablePad/DisposablePad.cs index 50538063..3e379c9c 100644 --- a/Source/DisposablePad/DisposablePad.cs +++ b/Source/DisposablePad/DisposablePad.cs @@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELDisposablePad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameWindow.IRenamable + public class ELDisposablePad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameDialog.IRenamable { [KSPField (isPersistant = false)] public string SpawnTransform; @@ -352,7 +352,7 @@ public void ShowUI () public void ShowRenameUI () { oldName = PadName; - ELRenameWindow.ShowGUI (this); + ELRenameDialog.OpenDialog (ELLocalization.RenameMicropad, this); } public void UpdateMenus (bool visible) diff --git a/Source/GUI/RenameWindow.cs b/Source/GUI/RenameWindow.cs deleted file mode 100644 index ea82f5d7..00000000 --- a/Source/GUI/RenameWindow.cs +++ /dev/null @@ -1,145 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KSP.IO; - -namespace ExtraplanetaryLaunchpads { - - [KSPAddon (KSPAddon.Startup.FlightAndEditor, false)] - public class ELRenameWindow: MonoBehaviour - { - public interface IRenamable { - string Name { get; set; } - void OnRename (); - } - - private static IRenamable target = null; - private static ELRenameWindow windowInstance = null; - private static Rect windowpos = new Rect(Screen.width * 0.35f,Screen.height * 0.1f,1,1); - const string fieldName = "RenameWindow.ExtraplanetaryLaunchpads"; - private static TextField nameField = new TextField (fieldName); - - void Awake () - { - windowInstance = this; - enabled = false; - } - - void OnDestroy () - { - Debug.Log("[ELRenameWindow] OnDestroy"); - windowInstance = null; - target = null; - } - - public static void HideGUI () - { - if (windowInstance != null) { - windowInstance.enabled = false; - } - ClearControlLock (); - } - - public static void ShowGUI (IRenamable renamable) - { - target = renamable; - nameField.text = renamable.Name; - if (windowInstance != null) { - windowInstance.enabled = true; - } - } - - void RenamePad () - { - if (target.Name != nameField.text) { - target.Name = nameField.text; - target.OnRename (); - } - } - - void RenameField () - { - GUILayout.BeginHorizontal (); - GUILayout.Label ("Rename launchpad: "); - - if (nameField.HandleInput ()) { - RenamePad (); - HideGUI (); - } - GUILayout.EndHorizontal (); - } - - void OKCancelButtons () - { - GUILayout.BeginHorizontal (); - GUILayout.FlexibleSpace (); - if (GUILayout.Button ("OK")) { - nameField.AcceptInput (); - RenamePad (); - HideGUI (); - } - GUILayout.FlexibleSpace (); - if (GUILayout.Button ("Cancel")) { - HideGUI (); - } - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - } - - void WindowGUI (int windowID) - { - GUILayout.BeginVertical (); - - RenameField (); - OKCancelButtons (); - - GUILayout.EndVertical (); - - GUI.DragWindow (new Rect (0, 0, 10000, 20)); - - } - - static void SetControlLock () - { - InputLockManager.SetControlLock ("EL_Rename_window_lock"); - } - - static void ClearControlLock () - { - InputLockManager.RemoveControlLock ("EL_Rename_window_lock"); - } - - void OnGUI () - { - GUI.skin = HighLogic.Skin; - windowpos = GUILayout.Window (GetInstanceID (), - windowpos, WindowGUI, - "Rename Launchpad", - GUILayout.Width(500)); - if (windowpos.Contains(Event.current.mousePosition)) { - SetControlLock (); - } else { - ClearControlLock (); - } - } - } -} diff --git a/Source/Makefile b/Source/Makefile index 0cb8ac3f..4ace077a 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -63,7 +63,6 @@ EL_FILES := \ GUI/DropDownList.cs \ GUI/EditorToolbar.cs \ GUI/ProgressBar.cs \ - GUI/RenameWindow.cs \ GUI/ResourceWindow.cs \ GUI/ScrollView.cs \ GUI/Styles.cs \ @@ -79,6 +78,7 @@ EL_FILES := \ UI/Localization.cs \ UI/MainWindow.cs \ UI/PadView.cs \ + UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ UI/ResourceLine.cs \ UI/ShipInfo.cs \ diff --git a/Source/Pad/Launchpad.cs b/Source/Pad/Launchpad.cs index 17b3b0c9..3fb4a15f 100644 --- a/Source/Pad/Launchpad.cs +++ b/Source/Pad/Launchpad.cs @@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELLaunchpad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameWindow.IRenamable + public class ELLaunchpad : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameDialog.IRenamable { [KSPField (isPersistant = false)] public float SpawnHeightOffset = 0.0f; @@ -298,7 +298,7 @@ public void ShowUI () public void ShowRenameUI () { oldName = PadName; - ELRenameWindow.ShowGUI (this); + ELRenameDialog.OpenDialog (ELLocalization.RenameLaunchpad, this); } public void UpdateMenus (bool visible) diff --git a/Source/Survey/SurveySite.cs b/Source/Survey/SurveySite.cs index 41c3b4b0..21e233e3 100644 --- a/Source/Survey/SurveySite.cs +++ b/Source/Survey/SurveySite.cs @@ -23,7 +23,7 @@ You should have received a copy of the GNU General Public License using KSP.IO; namespace ExtraplanetaryLaunchpads { - internal class SurveySite: ELRenameWindow.IRenamable + internal class SurveySite: ELRenameDialog.IRenamable { List stakes; diff --git a/Source/Survey/SurveyStation.cs b/Source/Survey/SurveyStation.cs index fc70025f..5eb32728 100644 --- a/Source/Survey/SurveyStation.cs +++ b/Source/Survey/SurveyStation.cs @@ -26,7 +26,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELSurveyStation : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameWindow.IRenamable + public class ELSurveyStation : PartModule, IModuleInfo, IPartMassModifier, ELBuildControl.IBuilder, ELControlInterface, ELWorkSink, ELRenameDialog.IRenamable { [KSPField (isPersistant = true, guiActive = true, guiName = "Pad name")] public string StationName = ""; @@ -202,7 +202,7 @@ void RenameSite () if (GUILayout.Button ("Rename Site", ELStyles.normal, GUILayout.ExpandWidth (false))) { if (site != null) { - ELRenameWindow.ShowGUI (site); + ELRenameDialog.OpenDialog (ELLocalization.RenameSite, site); } } GUI.enabled = en; @@ -400,7 +400,7 @@ public void ShowUI () public void ShowRenameUI () { oldName = StationName; - ELRenameWindow.ShowGUI (this); + ELRenameDialog.OpenDialog (ELLocalization.RenameSurveyStation, this); } public void UpdateMenus (bool visible) diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 6c74ce00..9015d3b4 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -52,5 +52,12 @@ public static class ELLocalization public static string TotalMass { get; } = "Total mass"; public static string BuildTime { get; } = "Build time"; public static string KerbalHours { get; } = "Kh"; + public static string RenameMicropad { get; } = "Rename Micro-pad"; + public static string RenameLaunchpad { get; } = "Rename Launchpad"; + public static string RenameSite { get; } = "Rename Site"; + public static string RenameSurveyStation { get; } = "Rename Survey Station"; + public static string Name { get; } = "Name"; + public static string OK { get; } = "OK"; + public static string Cancel { get; } = "Cancel"; } } diff --git a/Source/UI/RenameDialog.cs b/Source/UI/RenameDialog.cs new file mode 100644 index 00000000..79feefe1 --- /dev/null +++ b/Source/UI/RenameDialog.cs @@ -0,0 +1,188 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Reflection; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELRenameDialog : Window + { + public interface IRenamable { + string Name { get; set; } + void OnRename (); + } + + UIInputField nameField; + UIButton okButton; + UIButton cancelButton; + UIText version; + + IRenamable target; + + public override void CreateUI() + { + base.CreateUI (); + + this.Title ("Rename") + .Vertical() + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .PreferredSizeFitter (true, true) + .Anchor (AnchorPresets.MiddleCenter) + .Pivot (PivotPresets.TopLeft) + .PreferredWidth (500) + + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,true) + .FlexibleLayout (true, false) + .Add () + .Text (ELLocalization.Name) + .Alignment (TextAlignmentOptions.Left) + .FlexibleLayout (false, false) + .Finish () + .Add () + .PreferredSize (5, -1) + .Finish () + .Add (out nameField) + .OnSubmit (onSubmit) + .OnFocusGained (SetControlLock) + .OnFocusLost (ClearControlLock) + .FlexibleLayout (true, false) + .SizeDelta (0,0) + .Finish () + .Finish () + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .FlexibleLayout (true, false) + .Add () + .FlexibleLayout (1, -1) + .Finish () + .Add (out okButton) + .Text (ELLocalization.OK) + .OnClick (onOK) + .FlexibleLayout (1, -1) + .Finish () + .Add () + .FlexibleLayout (2, -1) + .Finish () + .Add (out cancelButton) + .Text (ELLocalization.Cancel) + .OnClick (onCancel) + .FlexibleLayout (1, -1) + .Finish () + .Add () + .FlexibleLayout (1, -1) + .Finish () + .Finish () + .Add (out version) + .Text (ELVersionReport.GetVersion ()) + .Alignment (TextAlignmentOptions.Center) + .Size (12) + .FlexibleLayout (true, false) + .Finish (); + Finish (); + } + + void onSubmit (string str) + { + target.Name = str; + target.OnRename (); + SetActive (false); + ClearControlLock (); + } + + void onOK () + { + target.Name = nameField.text; + target.OnRename (); + ClearControlLock (); + SetActive (false); + } + + void onCancel () + { + ClearControlLock (); + SetActive (false); + } + + public override void Style () + { + base.Style (); + } + + public void SetVisible (bool visible) + { + gameObject.SetActive (visible); + } + + ELRenameDialog SetTarget (IRenamable target) + { + this.target = target; + nameField.text = target.Name; + SetActive (true); + return this; + } + + static void SetControlLock (string str = null) + { + InputLockManager.SetControlLock ("ELRenameDialog_lock"); + } + + static void ClearControlLock (string str = null) + { + InputLockManager.RemoveControlLock ("ELRenameDialog_lock"); + } + + protected override void Awake () + { + GameEvents.onGameSceneSwitchRequested.Add (onGameSceneSwitchRequested); + } + + protected override void OnDestroy () + { + GameEvents.onGameSceneSwitchRequested.Remove (onGameSceneSwitchRequested); + } + + void onGameSceneSwitchRequested(GameEvents.FromToAction data) + { + // scene change is effectively Cancel :) + SetActive (false); + } + + static ELRenameDialog renameDialog; + + public static void OpenDialog (string title, IRenamable target) + { + if (!renameDialog) { + renameDialog = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELRenameDialog"); + } + renameDialog.SetTarget (target).Title (title); + } + } +} diff --git a/Source/UI/WindowManager.cs b/Source/UI/WindowManager.cs index 2e263c62..2a4a9372 100644 --- a/Source/UI/WindowManager.cs +++ b/Source/UI/WindowManager.cs @@ -159,7 +159,7 @@ public static void ToggleShipInfo () } static Canvas appCanvas; - static RectTransform appCanvasRect; + public static RectTransform appCanvasRect { get; private set; } static WindowInfo mainWindowInfo = new WindowInfo (); static ELMainWindow mainWindow; From 8648ba374bd970c499a97a9a065b6ecd97f63410 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 5 Oct 2020 19:27:39 +0900 Subject: [PATCH 043/150] Fix an NRE when resources go missing Caused by vessel self destructing :) --- Source/UI/CraftView.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index 7d052ddb..f8b6e6c5 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -54,6 +54,9 @@ public double AvailableAmount public double ResourceFraction { get { + if (this.available == null || this.required == null) { + return 0; + } double required = this.required.amount; double available = this.available.amount; From 2c5b9362369615595361ab9ddb10c90cf02eb986 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 6 Oct 2020 10:53:06 +0900 Subject: [PATCH 044/150] Default RM addVessels and useFlightID to true So far, useFlightID has always been true, though addVessels varies a bit. --- Source/BuildControl.cs | 11 ++++++----- Source/ResourceManager/ResourceManager.cs | 6 ++++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index 8a1147fe..2c49a511 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -430,7 +430,7 @@ internal void SetupCraftResources (Vessel vsl) { Part rootPart = vsl.parts[0].localRoot; craftResourceManager = new RMResourceManager (vsl.parts, rootPart, - false, true); + false); foreach (var br in buildCost.optional) { var amount = craftResources.ResourceAmount (br.name); craftResources.TransferResource (br.name, -amount); @@ -858,12 +858,13 @@ void FindVesselResources () //Debug.Log ($"[ELBuildControl] FindVesselResources pad {pad_parts.Count} craft {craft_parts.Count}"); string vesselName = builder.vessel.vesselName; - Part root = builder.part.localRoot; + Part vesselRoot = builder.part.localRoot; //Debug.Log ($"[ELBuildControl] FindVesselResources pad"); padResourceManager = new RMResourceManager (vesselName, - pad_parts, root, + pad_parts, + vesselRoot, craft_parts, - false, true); + false); if (craft_parts.Count > 0) { //Debug.Log ($"[ELBuildControl] FindVesselResources craft"); @@ -871,7 +872,7 @@ void FindVesselResources () craft_parts, craftRoot, null, - false, true); + false); } } diff --git a/Source/ResourceManager/ResourceManager.cs b/Source/ResourceManager/ResourceManager.cs index 09c36129..468ad04e 100644 --- a/Source/ResourceManager/ResourceManager.cs +++ b/Source/ResourceManager/ResourceManager.cs @@ -442,7 +442,8 @@ void DumpResourceSets () public RMResourceManager (string vesselName, IEnumerable parts, Part rootPart, HashSet excludeParts, - bool addVessels, bool useFlightID) + bool addVessels = true, + bool useFlightID = true) { this.useFlightID = useFlightID; this.addVessels = addVessels; @@ -458,7 +459,8 @@ public RMResourceManager (string vesselName, } public RMResourceManager (IEnumerable parts, Part rootPart, - bool addVessels, bool useFlightID) + bool addVessels = true, + bool useFlightID = true) { this.useFlightID = useFlightID; this.addVessels = addVessels; From 72cc03e00f1a4437a0bb11054342a147b6cce610 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 6 Oct 2020 11:39:23 +0900 Subject: [PATCH 045/150] Move the building stuff to its own view This will allow the main window to be used for multiple views (build manager, resource manager, ...) via tabs or similar, and also allow the build manager view to be used on another canvas (eg, a world-space canvas). --- Source/Makefile | 1 + Source/UI/BuildManagerView.cs | 88 +++++++++++++++++++++++++++++++++++ Source/UI/MainWindow.cs | 32 +++---------- 3 files changed, 95 insertions(+), 26 deletions(-) create mode 100644 Source/UI/BuildManagerView.cs diff --git a/Source/Makefile b/Source/Makefile index 4ace077a..4e203201 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -73,6 +73,7 @@ EL_FILES := \ Recycler/StateMachine.cs \ Target/Target.cs \ UI/BuildView.cs \ + UI/BuildManagerView.cs \ UI/CraftView.cs \ UI/IResourceLine.cs \ UI/Localization.cs \ diff --git a/Source/UI/BuildManagerView.cs b/Source/UI/BuildManagerView.cs new file mode 100644 index 00000000..69401982 --- /dev/null +++ b/Source/UI/BuildManagerView.cs @@ -0,0 +1,88 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ELBuildManagerView : Layout + { + ELStatusBar statusBar; + ELPadView padView; + ELCraftView craftView; + ELBuildView buildView; + ELTransferView transferView; + + public override void CreateUI() + { + base.CreateUI (); + + this.Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add(out statusBar, "StatusBar") + .Finish() + .Add(out padView, "PadView") + .Finish() + .Add(out craftView, "CraftView") + .Finish() + .Add(out buildView, "BuildView") + .Finish() + .Add(out transferView, "TransferView") + .Finish() + ; + + craftView.gameObject.SetActive (false); + buildView.gameObject.SetActive (false); + transferView.gameObject.SetActive (false); + padView.AddListener (craftView.UpdateControl); + padView.AddListener (buildView.UpdateControl); + padView.AddListener (transferView.UpdateControl); + } + + public override void Style () + { + base.Style (); + } + + public void SetVessel (Vessel vessel) + { + statusBar.SetVessel (vessel); + padView.SetVessel (vessel); + } + + public void SetControl (ELBuildControl control) + { + statusBar.SetVessel (control.builder.vessel); + padView.SetControl (control); + } + } +} diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index 9589a3c5..fa649665 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -30,15 +30,12 @@ namespace ExtraplanetaryLaunchpads { public class ELMainWindow : Window { - ELStatusBar statusBar; - ELPadView padView; - ELCraftView craftView; - ELBuildView buildView; - ELTransferView transferView; + ELBuildManagerView buildManager; public override void CreateUI() { base.CreateUI (); + Title (ELVersionReport.GetVersion ()) .Vertical() .ControlChildSize(true, true) @@ -48,24 +45,9 @@ public override void CreateUI() .Pivot(PivotPresets.TopLeft) .PreferredWidth(695) - .Add(out statusBar, "StatusBar") - .Finish() - .Add(out padView, "PadView") - .Finish() - .Add(out craftView, "CraftView") - .Finish() - .Add(out buildView, "BuildView") - .Finish() - .Add(out transferView, "TransferView") - .Finish() + .Add (out buildManager) + .Finish () .Finish(); - - craftView.gameObject.SetActive (false); - buildView.gameObject.SetActive (false); - transferView.gameObject.SetActive (false); - padView.AddListener (craftView.UpdateControl); - padView.AddListener (buildView.UpdateControl); - padView.AddListener (transferView.UpdateControl); } public override void Style () @@ -75,14 +57,12 @@ public override void Style () public void SetVessel (Vessel vessel) { - statusBar.SetVessel (vessel); - padView.SetVessel (vessel); + buildManager.SetVessel (vessel); } public void SetControl (ELBuildControl control) { - statusBar.SetVessel (control.builder.vessel); - padView.SetControl (control); + buildManager.SetControl (control); } public void SetVisible (bool visible) From 56e72224306bca697115d528b87927b28e1f82e4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 6 Oct 2020 18:37:51 +0900 Subject: [PATCH 046/150] Implement the basics of the resource manager view Still needs a lot of work, and I'm uncertain about using the resource bars, but the framework is in place. Need to sort out xfer/flow mode toggle sizes/labels and hook them up. --- KodeUI | 2 +- Source/Makefile | 6 +- Source/Settings.cs | 10 -- Source/UI/Localization.cs | 2 + Source/UI/MainWindow.cs | 6 +- Source/UI/ResourceGroup.cs | 127 ++++++++++++++++++++ Source/UI/ResourceGroupView.cs | 96 ++++++++++++++++ Source/UI/ResourceManagerView.cs | 191 +++++++++++++++++++++++++++++++ Source/UI/ResourceModule.cs | 103 +++++++++++++++++ Source/UI/ResourceModuleView.cs | 96 ++++++++++++++++ Source/toolbar/Toolbar.cs | 2 - 11 files changed, 626 insertions(+), 15 deletions(-) create mode 100644 Source/UI/ResourceGroup.cs create mode 100644 Source/UI/ResourceGroupView.cs create mode 100644 Source/UI/ResourceManagerView.cs create mode 100644 Source/UI/ResourceModule.cs create mode 100644 Source/UI/ResourceModuleView.cs diff --git a/KodeUI b/KodeUI index 8de02f71..6a37f966 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 8de02f718d45deba197dbd2a2cff9d140c42eb5a +Subproject commit 6a37f966838dca31b4c38064e5482a0e724ec81c diff --git a/Source/Makefile b/Source/Makefile index 4e203201..16b01809 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -63,7 +63,6 @@ EL_FILES := \ GUI/DropDownList.cs \ GUI/EditorToolbar.cs \ GUI/ProgressBar.cs \ - GUI/ResourceWindow.cs \ GUI/ScrollView.cs \ GUI/Styles.cs \ GUI/TextField.cs \ @@ -81,7 +80,12 @@ EL_FILES := \ UI/PadView.cs \ UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ + UI/ResourceGroup.cs \ + UI/ResourceGroupView.cs \ UI/ResourceLine.cs \ + UI/ResourceManagerView.cs \ + UI/ResourceModule.cs \ + UI/ResourceModuleView.cs \ UI/ShipInfo.cs \ UI/ShipInfoWindow.cs \ UI/StatusBar.cs \ diff --git a/Source/Settings.cs b/Source/Settings.cs index 0c1bc4b4..4b261809 100644 --- a/Source/Settings.cs +++ b/Source/Settings.cs @@ -200,14 +200,6 @@ void ParseWindowManager (ConfigNode settings) } } - void ParseResourceWindow (ConfigNode settings) - { - if (settings.HasNode ("ResourceWindow")) { - var node = settings.GetNode ("ResourceWindow"); - ELResourceWindow.LoadSettings (node); - } - } - public override void OnLoad (ConfigNode config) { //Debug.Log (String.Format ("[EL] Settings load")); @@ -223,7 +215,6 @@ public override void OnLoad (ConfigNode config) ParseShowCraftHull (settings); ParseDebugCraftHull (settings); ParseWindowManager (settings); - ParseResourceWindow (settings); if (HighLogic.LoadedScene == GameScenes.SPACECENTER) { enabled = true; @@ -243,7 +234,6 @@ public override void OnSave(ConfigNode config) settings.AddValue ("DebugCraftHull", DebugCraftHull); ELWindowManager.SaveSettings (settings.AddNode ("WindowManager")); - ELResourceWindow.SaveSettings (settings.AddNode ("ResourceWindow")); } void LoadGlobalSettings () diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 9015d3b4..ac463a6a 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -59,5 +59,7 @@ public static class ELLocalization public static string Name { get; } = "Name"; public static string OK { get; } = "OK"; public static string Cancel { get; } = "Cancel"; + public static string StartTransfer { get; } = "Start Transfer"; + public static string StopTransfer { get; } = "Stop Transfer"; } } diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index fa649665..bab5bf1c 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -31,6 +31,7 @@ namespace ExtraplanetaryLaunchpads { public class ELMainWindow : Window { ELBuildManagerView buildManager; + ELResourceManagerView resourceManager; public override void CreateUI() { @@ -47,6 +48,8 @@ public override void CreateUI() .Add (out buildManager) .Finish () + .Add (out resourceManager) + .Finish () .Finish(); } @@ -58,6 +61,7 @@ public override void Style () public void SetVessel (Vessel vessel) { buildManager.SetVessel (vessel); + resourceManager.SetVessel (vessel); } public void SetControl (ELBuildControl control) @@ -67,7 +71,7 @@ public void SetControl (ELBuildControl control) public void SetVisible (bool visible) { - gameObject.SetActive (visible); + SetActive (visible); } } } diff --git a/Source/UI/ResourceGroup.cs b/Source/UI/ResourceGroup.cs new file mode 100644 index 00000000..1971d61f --- /dev/null +++ b/Source/UI/ResourceGroup.cs @@ -0,0 +1,127 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ResourceGroup : IResourceLine + { + RMResourceInfo resource; +#region IResourceLine + public string ResourceName { get { return resourceName; } } + public string ResourceInfo { get { return null; } } + public double ResourceFraction + { + get { + double maxAmount = resource.maxAmount; + if (maxAmount <= 0) { + return 0; + } + double amount = resource.amount; + return amount / maxAmount; + } + } + public double BuildAmount { get { return resource.amount; } } + public double AvailableAmount { get { return resource.maxAmount; } } +#endregion + public string resourceName { get; } + public bool isOpen { get; set; } + public ResourceModule.List modules { get; private set; } + ResourceModule.Dict moduleDict; + + public void BuildModules (RMResourceManager manager) + { + var liveSets = new HashSet (); + for (int i = 0; i < manager.resourceSets.Count; i++) { + var set = manager.resourceSets[i]; + if (!set.resources.ContainsKey (resourceName)) { + continue; + } + string moduleName = set.name; + liveSets.Add (moduleName); + if (moduleDict.ContainsKey (moduleName)) { + Debug.Log ($"[ResourceGroup] BuildModules updating {moduleName}"); + var mod = moduleDict[moduleName]; + mod.set = set; + } else { + Debug.Log ($"[ResourceGroup] BuildModules adding {moduleName}"); + var mod = new ResourceModule (set, resourceName); + moduleDict[moduleName] = mod; + modules.Add (mod); + } + } + + for (int i = modules.Count; i-- > 0; ) { + if (!liveSets.Contains(modules[i].name)) { + Debug.Log ($"[ResourceGroup] BuildModules removing {modules[i].name}"); + moduleDict.Remove (modules[i].name); + modules.RemoveAt (i); + } + } + } + + public ResourceGroup (string resourceName, RMResourceManager manager) + { + isOpen = false; + this.resourceName = resourceName; + resource = manager.masterSet.resources[resourceName]; + modules = new ResourceModule.List (); + moduleDict = new ResourceModule.Dict (); + + BuildModules (manager); + } + + public class Dict : Dictionary { } + public class List : List, UIKit.IListObject + { + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Resource (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var view = obj.GetComponent (); + view.Resource (this[index]); + } + } + } +} diff --git a/Source/UI/ResourceGroupView.cs b/Source/UI/ResourceGroupView.cs new file mode 100644 index 00000000..9e8b2ce0 --- /dev/null +++ b/Source/UI/ResourceGroupView.cs @@ -0,0 +1,96 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ELResourceGroupView : Layout + { + ResourceGroup resource; + + UIToggle openToggle; + ELResourceLine resourceLine; + Layout moduleView; + public Layout ModuleView { get { return moduleView; } } + + public override void CreateUI() + { + base.CreateUI (); + + this.Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .Add () + .Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add () + .PreferredSize (32, -1) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Add (out openToggle) + .OnValueChanged (SetOpen) + .AspectRatioSizeFitter (AspectRatioFitter.AspectMode.FitInParent, 1) + .Finish () + .Finish () + .Add (out resourceLine) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Add (out moduleView) + .Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .Finish () + ; + moduleView.SetActive (false); + } + + void SetOpen (bool open) + { + moduleView.SetActive (open); + resource.isOpen = open; + } + + public ELResourceGroupView Resource (ResourceGroup resource) + { + this.resource = resource; + resourceLine.Resource (resource); + resource.modules.Content = moduleView; + UIKit.UpdateListContent (resource.modules); + SetOpen (resource.isOpen); + openToggle.SetIsOnWithoutNotify (resource.isOpen); + return this; + } + } +} diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs new file mode 100644 index 00000000..a99263fd --- /dev/null +++ b/Source/UI/ResourceManagerView.cs @@ -0,0 +1,191 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public enum XferState { + Hold, + In, + Out, + }; + + public class ELResourceManagerView : Layout + { + /*class TransferResource : IResourceLine + { + RMResourceInfo resource; + + public string ResourceName { get { return resource.name; } } + public string ResourceInfo { get { return null; } } + public double BuildAmount { get { return resource.amount; } } + public double AvailableAmount { get { return resource.maxAmount; } } + public double ResourceFraction + { + get { + return resource.amount / resource.maxAmount; + } + } + + public TransferResource (RMResourceInfo resource) + { + this.resource = resource; + } + }*/ + + ResourceGroup.List resourceGroups; + ResourceGroup.Dict resourceGroupDict; + ScrollView resourceView; + UIButton transferButton; + + public override void CreateUI() + { + if (resourceGroups == null) { + resourceGroups = new ResourceGroup.List (); + resourceGroupDict = new ResourceGroup.Dict (); + } + + base.CreateUI (); + + var leftMin = new Vector2 (0, 0); + var leftMax = new Vector2 (0.5f, 1); + var rightMin = new Vector2 (0.5f, 0); + var rightMax = new Vector2 (1, 1); + + UIScrollbar scrollbar; + this.Vertical () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + + .Add() + .Background("KodeUI/Default/background") + .BackgroundColor(UnityEngine.Color.white) + .Vertical() + .Padding(8) + .ControlChildSize(true, true) + .ChildForceExpand(false, false) + .Anchor(AnchorPresets.HorStretchTop) + .FlexibleLayout(true,true) + .PreferredHeight(300) + .Add (out resourceView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Add (out scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () + .Add (out transferButton) + .Text (ELLocalization.StartTransfer) + .OnClick (ToggleTransfer) + .FlexibleLayout (true, true) + .Finish() + .Finish(); + + resourceView.VerticalScrollbar = scrollbar; + resourceView.Viewport.FlexibleLayout (true, true); + resourceView.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .WidthDelta(0) + .Finish (); + + resourceGroups.Content = resourceView.Content; + + transferButton.interactable = false; + } + + void ToggleTransfer () + { + } + + void RebuildResources (RMResourceManager resourceManager) + { + var set = new HashSet (); + foreach (var s in resourceManager.resourceSets) { + foreach (string r in s.resources.Keys) { + set.Add (r); + } + } + + foreach (var res in set) { + if (resourceGroupDict.ContainsKey (res)) { + Debug.Log ($"[ELResourceManagerView] RebuildResources updating {res}"); + resourceGroupDict[res].BuildModules (resourceManager); + } else { + Debug.Log ($"[ELResourceManagerView] RebuildResources adding {res}"); + var group = new ResourceGroup (res, resourceManager); + resourceGroupDict[res] = group; + resourceGroups.Add (group); + } + } + + for (int i = resourceGroups.Count; i-- > 0; ) { + var group = resourceGroups[i]; + if (!set.Contains (group.resourceName)) { + Debug.Log ($"[ELResourceManagerView] RebuildResources removing {group.resourceName}"); + resourceGroupDict.Remove (group.resourceName); + resourceGroups.RemoveAt (i); + } + } + + UIKit.UpdateListContent (resourceGroups); + } + + IEnumerator WaitAndRebuildResources () + { + int count = 5; + while (count-- > 0) { + yield return null; + } + var vessel = FlightGlobals.ActiveVessel; + if (!vessel) { + yield break; + } + SetVessel (vessel); + } + + public void SetVessel (Vessel vessel) + { + var parts = vessel.parts; + Part rootPart = parts[0].localRoot; + var manager = new RMResourceManager (parts, rootPart); + RebuildResources (manager); + } + } +} diff --git a/Source/UI/ResourceModule.cs b/Source/UI/ResourceModule.cs new file mode 100644 index 00000000..3561db17 --- /dev/null +++ b/Source/UI/ResourceModule.cs @@ -0,0 +1,103 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ResourceModule : IResourceLine + { + string resourceName; +#region IResourceLine + public string ResourceName { get { return set.name; } } + public string ResourceInfo { get { return null; } } + public double ResourceFraction + { + get { + double maxAmount = set.ResourceCapacity (resourceName); + if (maxAmount <= 0) { + return 0; + } + double amount = set.ResourceAmount (resourceName); + return amount / maxAmount; + } + } + public double BuildAmount + { + get { return set.ResourceAmount (resourceName); } + } + public double AvailableAmount + { + get { + return set.ResourceCapacity (resourceName); + } + } +#endregion + public string name { get { return set.name; } } + public RMResourceSet set { get; set; } + public XferState xferState { get; private set; } + public bool flowState { + get { return set.GetFlowState (resourceName); } + set { set.SetFlowState (resourceName, value); } + } + + public ResourceModule (RMResourceSet set, string resourceName) + { + this.set = set; + this.resourceName = resourceName; + xferState = XferState.Hold; + } + + public class Dict : Dictionary { } + public class List : List, UIKit.IListObject + { + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Module (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var view = obj.GetComponent (); + view.Module (this[index]); + } + } + } +} diff --git a/Source/UI/ResourceModuleView.cs b/Source/UI/ResourceModuleView.cs new file mode 100644 index 00000000..b295a40d --- /dev/null +++ b/Source/UI/ResourceModuleView.cs @@ -0,0 +1,96 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Reflection; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +using KSP.IO; +using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; + +namespace ExtraplanetaryLaunchpads { + + public class ELResourceModuleView : Layout + { + ELResourceLine resourceLine; + UIToggle holdToggle; + UIToggle inToggle; + UIToggle outToggle; + UIToggle flowToggle; + + public override void CreateUI() + { + base.CreateUI (); + + ToggleGroup modeGroup; + + this.Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .ToggleGroup (out modeGroup) + + .Add () + .SizeDelta (0, 0) + .PreferredSize (32, -1) + .Finish () + .Add (out resourceLine) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () + .Add (out holdToggle) + .Group (modeGroup) + .OnValueChanged ((b) => { SetState (b, XferState.Hold); }) + .Finish () + .Add (out inToggle) + .Group (modeGroup) + .OnValueChanged ((b) => { SetState (b, XferState.In); }) + .Finish () + .Add (out outToggle) + .Group (modeGroup) + .OnValueChanged ((b) => { SetState (b, XferState.Out); }) + .Finish () + .Add (out flowToggle) + .OnValueChanged (SetFlowState) + .Finish () + ; + } + + void SetState (bool on, XferState state) + { + if (on) { + } + } + + void SetFlowState (bool on) + { + } + + public ELResourceModuleView Module (ResourceModule module) + { + resourceLine.Resource (module); + return this; + } + } +} diff --git a/Source/toolbar/Toolbar.cs b/Source/toolbar/Toolbar.cs index c795d6fb..cb89dbf3 100644 --- a/Source/toolbar/Toolbar.cs +++ b/Source/toolbar/Toolbar.cs @@ -118,7 +118,6 @@ public class ELToolbar_BuildWindow : MonoBehaviour public void Awake () { ELAppButton.Toggle += ELWindowManager.ToggleBuildWindow; - ELAppButton.RightToggle += ELResourceWindow.ToggleGUI; if (ToolbarManager.Instance == null) { return; @@ -136,7 +135,6 @@ void OnDestroy() ELBuildWindowButton.Destroy (); } ELAppButton.Toggle -= ELWindowManager.ToggleBuildWindow; - ELAppButton.RightToggle -= ELResourceWindow.ToggleGUI; } } From 87778f08b8ae3999c8d78e1cad099f9de35178dd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 09:29:33 +0900 Subject: [PATCH 047/150] Get xfer/flow toggles laid out and flow connected --- Source/Makefile | 2 + Source/UI/Localization.cs | 3 ++ Source/UI/MiniToggle.cs | 73 +++++++++++++++++++++++++++++++++ Source/UI/ResourceGroupView.cs | 1 - Source/UI/ResourceModuleView.cs | 33 ++++++++++----- Source/UI/ToggleText.cs | 71 ++++++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 11 deletions(-) create mode 100644 Source/UI/MiniToggle.cs create mode 100644 Source/UI/ToggleText.cs diff --git a/Source/Makefile b/Source/Makefile index 16b01809..9be70b70 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -77,6 +77,7 @@ EL_FILES := \ UI/IResourceLine.cs \ UI/Localization.cs \ UI/MainWindow.cs \ + UI/MiniToggle.cs \ UI/PadView.cs \ UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ @@ -90,6 +91,7 @@ EL_FILES := \ UI/ShipInfoWindow.cs \ UI/StatusBar.cs \ UI/TextInfoLine.cs \ + UI/ToggleText.cs \ UI/TransferView.cs \ UI/WindowManager.cs \ Workshop/ConstructionSkill.cs \ diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index ac463a6a..08b27334 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -61,5 +61,8 @@ public static class ELLocalization public static string Cancel { get; } = "Cancel"; public static string StartTransfer { get; } = "Start Transfer"; public static string StopTransfer { get; } = "Stop Transfer"; + public static string Hold { get; } = "Hold"; + public static string In { get; } = "In"; + public static string Out { get; } = "Out"; } } diff --git a/Source/UI/MiniToggle.cs b/Source/UI/MiniToggle.cs new file mode 100644 index 00000000..3cca5dd9 --- /dev/null +++ b/Source/UI/MiniToggle.cs @@ -0,0 +1,73 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class MiniToggle : Layout + { + UIToggle toggle; + + public override void CreateUI() + { + var toggleMin = new Vector2 (0, 0.25f); + var toggleMax = new Vector2 (1, 0.75f); + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .ChildAlignment (TextAnchor.UpperCenter) + .SizeDelta (0, 0) + .MinSize (20, -1) + .Add () + .DoPreferredWidth (true) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Add (out toggle) + .Anchor(toggleMin, toggleMax) + .AspectRatioSizeFitter (AspectRatioFitter.AspectMode.HeightControlsWidth, 1) + .SizeDelta (0, 0) + .Finish () + .Finish () + ; + } + + public MiniToggle Group (ToggleGroup group) + { + toggle.Group (group); + return this; + } + + public MiniToggle OnValueChanged (UnityAction action) + { + toggle.OnValueChanged (action); + return this; + } + + public MiniToggle SetIsOnWithoutNotify (bool on) + { + toggle.SetIsOnWithoutNotify (on); + return this; + } + } +} diff --git a/Source/UI/ResourceGroupView.cs b/Source/UI/ResourceGroupView.cs index 9e8b2ce0..da59be21 100644 --- a/Source/UI/ResourceGroupView.cs +++ b/Source/UI/ResourceGroupView.cs @@ -73,7 +73,6 @@ public override void CreateUI() .ChildForceExpand(false,false) .Finish () ; - moduleView.SetActive (false); } void SetOpen (bool open) diff --git a/Source/UI/ResourceModuleView.cs b/Source/UI/ResourceModuleView.cs index b295a40d..35b8701f 100644 --- a/Source/UI/ResourceModuleView.cs +++ b/Source/UI/ResourceModuleView.cs @@ -34,11 +34,13 @@ namespace ExtraplanetaryLaunchpads { public class ELResourceModuleView : Layout { + ResourceModule module; + ELResourceLine resourceLine; - UIToggle holdToggle; - UIToggle inToggle; - UIToggle outToggle; - UIToggle flowToggle; + ToggleText holdToggle; + ToggleText inToggle; + ToggleText outToggle; + MiniToggle flowToggle; public override void CreateUI() { @@ -49,29 +51,37 @@ public override void CreateUI() this.Horizontal () .ControlChildSize(true, true) .ChildForceExpand(false,false) + .Padding (0, 8, 0, 0) .ToggleGroup (out modeGroup) - .Add () - .SizeDelta (0, 0) .PreferredSize (32, -1) + .SizeDelta (0, 0) .Finish () .Add (out resourceLine) .FlexibleLayout (true, false) .SizeDelta (0, 0) .Finish () - .Add (out holdToggle) + .Add (out holdToggle) .Group (modeGroup) + .Text (ELLocalization.Hold) .OnValueChanged ((b) => { SetState (b, XferState.Hold); }) .Finish () - .Add (out inToggle) + .Add (out inToggle) .Group (modeGroup) + .Text (ELLocalization.In) .OnValueChanged ((b) => { SetState (b, XferState.In); }) .Finish () - .Add (out outToggle) + .Add (out outToggle) .Group (modeGroup) + .Text (ELLocalization.Out) .OnValueChanged ((b) => { SetState (b, XferState.Out); }) .Finish () - .Add (out flowToggle) + .Add () + .PreferredSize (8, -1) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Finish () + .Add (out flowToggle) .OnValueChanged (SetFlowState) .Finish () ; @@ -85,11 +95,14 @@ void SetState (bool on, XferState state) void SetFlowState (bool on) { + module.flowState = on; } public ELResourceModuleView Module (ResourceModule module) { + this.module = module; resourceLine.Resource (module); + flowToggle.SetIsOnWithoutNotify (module.flowState); return this; } } diff --git a/Source/UI/ToggleText.cs b/Source/UI/ToggleText.cs new file mode 100644 index 00000000..347248be --- /dev/null +++ b/Source/UI/ToggleText.cs @@ -0,0 +1,71 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ToggleText : Layout + { + MiniToggle toggle; + UIText label; + + public override void CreateUI() + { + var toggleMin = new Vector2 (0, 0.25f); + var toggleMax = new Vector2 (1, 0.75f); + var textMargins = new Vector4 (5, 5, 10, 10); + this.Horizontal () + .ControlChildSize(true, true) + .ChildForceExpand(false,false) + .SizeDelta(0, 0) + .Add (out toggle) + .SizeDelta (0, 0) + .Finish () + .Add (out label) + .Alignment (TextAlignmentOptions.Left) + .Margin (textMargins) + .SizeDelta(0, 0) + .Finish () + ; + } + + public ToggleText Group (ToggleGroup group) + { + toggle.Group (group); + return this; + } + + public ToggleText Text (string text) + { + label.Text (text); + return this; + } + + public ToggleText OnValueChanged (UnityAction action) + { + toggle.OnValueChanged (action); + return this; + } + } +} From 4523d0ec7624c24faff7ab9a073d56b4dbbca735 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 10:11:37 +0900 Subject: [PATCH 048/150] Use mini toggle for resource groups Much nicer :) --- Source/UI/ResourceGroupView.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Source/UI/ResourceGroupView.cs b/Source/UI/ResourceGroupView.cs index da59be21..cde64c42 100644 --- a/Source/UI/ResourceGroupView.cs +++ b/Source/UI/ResourceGroupView.cs @@ -36,7 +36,7 @@ public class ELResourceGroupView : Layout { ResourceGroup resource; - UIToggle openToggle; + MiniToggle openToggle; ELResourceLine resourceLine; Layout moduleView; public Layout ModuleView { get { return moduleView; } } @@ -53,14 +53,11 @@ public override void CreateUI() .ControlChildSize(true, true) .ChildForceExpand(false,false) - .Add () + .Add (out openToggle) + .OnValueChanged (SetOpen) .PreferredSize (32, -1) .FlexibleLayout (false, true) .SizeDelta (0, 0) - .Add (out openToggle) - .OnValueChanged (SetOpen) - .AspectRatioSizeFitter (AspectRatioFitter.AspectMode.FitInParent, 1) - .Finish () .Finish () .Add (out resourceLine) .FlexibleLayout (true, false) From 7fdb54fee27eacf936cf7a6f8870b1798d404b18 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 10:13:21 +0900 Subject: [PATCH 049/150] Implement the view side of transfer state setting Still need to sort out the controller side. --- Source/UI/ResourceModule.cs | 2 +- Source/UI/ResourceModuleView.cs | 4 ++++ Source/UI/ToggleText.cs | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/UI/ResourceModule.cs b/Source/UI/ResourceModule.cs index 3561db17..5e8995dd 100644 --- a/Source/UI/ResourceModule.cs +++ b/Source/UI/ResourceModule.cs @@ -62,7 +62,7 @@ public double AvailableAmount #endregion public string name { get { return set.name; } } public RMResourceSet set { get; set; } - public XferState xferState { get; private set; } + public XferState xferState { get; set; } public bool flowState { get { return set.GetFlowState (resourceName); } set { set.SetFlowState (resourceName, value); } diff --git a/Source/UI/ResourceModuleView.cs b/Source/UI/ResourceModuleView.cs index 35b8701f..a8968ccf 100644 --- a/Source/UI/ResourceModuleView.cs +++ b/Source/UI/ResourceModuleView.cs @@ -90,6 +90,7 @@ public override void CreateUI() void SetState (bool on, XferState state) { if (on) { + module.xferState = state; } } @@ -102,6 +103,9 @@ public ELResourceModuleView Module (ResourceModule module) { this.module = module; resourceLine.Resource (module); + holdToggle.SetIsOnWithoutNotify (module.xferState == XferState.Hold); + inToggle.SetIsOnWithoutNotify (module.xferState == XferState.In); + outToggle.SetIsOnWithoutNotify (module.xferState == XferState.Out); flowToggle.SetIsOnWithoutNotify (module.flowState); return this; } diff --git a/Source/UI/ToggleText.cs b/Source/UI/ToggleText.cs index 347248be..59404d69 100644 --- a/Source/UI/ToggleText.cs +++ b/Source/UI/ToggleText.cs @@ -67,5 +67,11 @@ public ToggleText OnValueChanged (UnityAction action) toggle.OnValueChanged (action); return this; } + + public ToggleText SetIsOnWithoutNotify (bool on) + { + toggle.SetIsOnWithoutNotify (on); + return this; + } } } From 21a33090a07e99909de698c3c5fc62d96e42af2e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 10:15:30 +0900 Subject: [PATCH 050/150] Implement module highlighting Nice to see that working again :) --- Source/UI/ResourceModule.cs | 31 +++++++++++++++++++++++++++++++ Source/UI/ResourceModuleView.cs | 17 ++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/Source/UI/ResourceModule.cs b/Source/UI/ResourceModule.cs index 5e8995dd..392d0939 100644 --- a/Source/UI/ResourceModule.cs +++ b/Source/UI/ResourceModule.cs @@ -75,6 +75,37 @@ public ResourceModule (RMResourceSet set, string resourceName) xferState = XferState.Hold; } + static void HighlightPart (Part part, bool on) + { + if (on) { + part.SetHighlightColor (XKCDColors.LightSeaGreen); + part.SetHighlight (true, false); + } else { + part.SetHighlightDefault (); + } + } + + static void HighlightSet (RMResourceSet set, string res, bool on) + { + RMResourceInfo info; + if (!set.resources.TryGetValue (res, out info)) { + return; + } + for ( int i = info.containers.Count; i-- > 0; ) { + var c = info.containers[i]; + if (c is PartResourceContainer pc) { + HighlightPart (pc.part, on); + } else if (c is ResourceSetContainer sc) { + HighlightSet (sc.set, res, on); + } + } + } + + public void HighlightModule (bool on) + { + HighlightSet (set, resourceName, on); + } + public class Dict : Dictionary { } public class List : List, UIKit.IListObject { diff --git a/Source/UI/ResourceModuleView.cs b/Source/UI/ResourceModuleView.cs index a8968ccf..bcafcf98 100644 --- a/Source/UI/ResourceModuleView.cs +++ b/Source/UI/ResourceModuleView.cs @@ -23,6 +23,7 @@ You should have received a copy of the GNU General Public License using System.Linq; using UnityEngine; using UnityEngine.UI; +using UnityEngine.EventSystems; using TMPro; using KodeUI; @@ -32,7 +33,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELResourceModuleView : Layout + public class ELResourceModuleView : Layout, IPointerEnterHandler, IPointerExitHandler { ResourceModule module; @@ -46,6 +47,8 @@ public override void CreateUI() { base.CreateUI (); + gameObject.AddComponent(); + ToggleGroup modeGroup; this.Horizontal () @@ -90,6 +93,7 @@ public override void CreateUI() void SetState (bool on, XferState state) { if (on) { + Debug.Log ($"[ELResourceModuleView] SetState {state}"); module.xferState = state; } } @@ -109,5 +113,16 @@ public ELResourceModuleView Module (ResourceModule module) flowToggle.SetIsOnWithoutNotify (module.flowState); return this; } +#region OnPointerEnter/Exit + public void OnPointerEnter (PointerEventData eventData) + { + module.HighlightModule (true); + } + + public void OnPointerExit (PointerEventData eventData) + { + module.HighlightModule (false); + } +#endregion } } From abf70f68b451e40e2829e417380e6b48a926d565 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 11:34:44 +0900 Subject: [PATCH 051/150] Add a transfer control Just need to figure out how to connect it to the resource modules. --- Source/Makefile | 1 + Source/UI/ResourceXferControl.cs | 120 +++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 Source/UI/ResourceXferControl.cs diff --git a/Source/Makefile b/Source/Makefile index 9be70b70..20699a37 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -87,6 +87,7 @@ EL_FILES := \ UI/ResourceManagerView.cs \ UI/ResourceModule.cs \ UI/ResourceModuleView.cs \ + UI/ResourceXferControl.cs \ UI/ShipInfo.cs \ UI/ShipInfoWindow.cs \ UI/StatusBar.cs \ diff --git a/Source/UI/ResourceXferControl.cs b/Source/UI/ResourceXferControl.cs new file mode 100644 index 00000000..5e3d3be7 --- /dev/null +++ b/Source/UI/ResourceXferControl.cs @@ -0,0 +1,120 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ResourceXferControl + { + class XferSet : Dictionary { } + XferSet dstSets; + XferSet srcSets; + + public ResourceXferControl() + { + dstSets = new XferSet (); + srcSets = new XferSet (); + } + + public void Clear () + { + dstSets.Clear (); + srcSets.Clear (); + } + + void AddSet (XferSet xferSet, RMResourceSet set, string resourceName) + { + if (!xferSet.ContainsKey (resourceName)) { + xferSet[resourceName] = new RMResourceSet (); + xferSet[resourceName].balanced = true; + } + xferSet[resourceName].AddSet (set); + } + + void RemoveSet (XferSet xferSet, RMResourceSet set, string resourceName) + { + if (xferSet.ContainsKey (resourceName)) { + var s = xferSet[resourceName]; + s.RemoveSet (set); + if (s.resources.Count < 1) { + xferSet.Remove (resourceName); + } + } + } + + public void AddDestination (RMResourceSet set, string resourceName) + { + AddSet (dstSets, set, resourceName); + } + + public void RemoveDestination (RMResourceSet set, string resourceName) + { + RemoveSet (dstSets, set, resourceName); + } + + public void AddSource (RMResourceSet set, string resourceName) + { + AddSet (srcSets, set, resourceName); + } + + public void RemoveSource (RMResourceSet set, string resourceName) + { + RemoveSet (srcSets, set, resourceName); + } + + public bool TransferResources (double deltaTime) + { + bool didSomething = false; + foreach (string res in dstSets.Keys) { + var dst = dstSets[res]; + if (!srcSets.ContainsKey (res)) { + continue; + } + var src = srcSets[res]; + + double amount = dst.ResourceCapacity (res) / 20; + amount *= deltaTime; + + // FIXME heat + double srem = src.TransferResource (res, -amount); + // srem (amount not pulled) will be negative + if (srem == -amount) { + // could not pull any + continue; + } + amount += srem; + + double drem = dst.TransferResource (res, amount); + if (drem != amount) { + didSomething = true; + } + // return any untransfered amount back to source + src.TransferResource (res, drem); + } + return didSomething; + } + } +} From 80b4330ee927b91f0840ea819433a495a1ca6b82 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 15:08:40 +0900 Subject: [PATCH 052/150] Get resource module src/dst manipulation working Now for the actual transfer... --- Source/Makefile | 2 +- Source/ResourceManager/ResourceManager.cs | 32 +++++++++++++++++ .../ResourceXferControl.cs | 35 +++++++++++++++++++ Source/UI/ResourceGroup.cs | 2 +- Source/UI/ResourceManagerView.cs | 33 ++++------------- Source/UI/ResourceModule.cs | 15 ++++++-- 6 files changed, 88 insertions(+), 31 deletions(-) rename Source/{UI => ResourceManager}/ResourceXferControl.cs (76%) diff --git a/Source/Makefile b/Source/Makefile index 20699a37..7706a0e8 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -46,6 +46,7 @@ EL_FILES := \ ResourceManager/ResourceManager.cs \ ResourceManager/ResourceSet.cs \ ResourceManager/ResourceSetContainer.cs \ + ResourceManager/ResourceXferControl.cs \ Survey/Billboard.cs \ Survey/Points.cs \ Survey/SiteBody.cs \ @@ -87,7 +88,6 @@ EL_FILES := \ UI/ResourceManagerView.cs \ UI/ResourceModule.cs \ UI/ResourceModuleView.cs \ - UI/ResourceXferControl.cs \ UI/ShipInfo.cs \ UI/ShipInfoWindow.cs \ UI/StatusBar.cs \ diff --git a/Source/ResourceManager/ResourceManager.cs b/Source/ResourceManager/ResourceManager.cs index 468ad04e..e2f49370 100644 --- a/Source/ResourceManager/ResourceManager.cs +++ b/Source/ResourceManager/ResourceManager.cs @@ -28,6 +28,12 @@ namespace ExtraplanetaryLaunchpads { using KAS; + public enum XferState { + Hold, + In, + Out, + }; + public class RMResourceManager { class ConnectedPartSet { @@ -70,6 +76,32 @@ public void Clear () bool useFlightID; bool addVessels; + public ResourceXferControl xferControl { get; private set; } + + public ResourceXferControl CreateXferControl () + { + if (xferControl == null) { + xferControl = new ResourceXferControl (); + } + return xferControl; + } + + public void MoveSet (XferState from, XferState to, RMResourceSet set, + string resourceName) + { + if (from == XferState.In) { + xferControl.RemoveDestination (set, resourceName); + } else if (from == XferState.Out) { + xferControl.RemoveSource (set, resourceName); + } + if (to == XferState.In) { + xferControl.AddDestination (set, resourceName); + } else if (to == XferState.Out) { + xferControl.AddSource (set, resourceName); + } + xferControl.CheckTransfer (); + } + void ExpandPartMap (IEnumerable parts) { foreach (Part p in parts) { diff --git a/Source/UI/ResourceXferControl.cs b/Source/ResourceManager/ResourceXferControl.cs similarity index 76% rename from Source/UI/ResourceXferControl.cs rename to Source/ResourceManager/ResourceXferControl.cs index 5e3d3be7..11c3fc6a 100644 --- a/Source/UI/ResourceXferControl.cs +++ b/Source/ResourceManager/ResourceXferControl.cs @@ -33,6 +33,22 @@ class XferSet : Dictionary { } XferSet dstSets; XferSet srcSets; + public delegate void OnTransferableChanged (); + public OnTransferableChanged onTransferableChanged = delegate { }; + + bool _canTransfer; + public bool canTransfer + { + get { return _canTransfer; } + set { + bool changed = _canTransfer != value; + _canTransfer = value; + if (changed) { + onTransferableChanged (); + } + } + } + public ResourceXferControl() { dstSets = new XferSet (); @@ -67,26 +83,45 @@ void RemoveSet (XferSet xferSet, RMResourceSet set, string resourceName) public void AddDestination (RMResourceSet set, string resourceName) { + Debug.Log ($"[ResourceXferControl] AddDestination {set.name} {resourceName}"); AddSet (dstSets, set, resourceName); } public void RemoveDestination (RMResourceSet set, string resourceName) { + Debug.Log ($"[ResourceXferControl] RemoveDestination {set.name} {resourceName}"); RemoveSet (dstSets, set, resourceName); } public void AddSource (RMResourceSet set, string resourceName) { + Debug.Log ($"[ResourceXferControl] AddSource {set.name} {resourceName}"); AddSet (srcSets, set, resourceName); } public void RemoveSource (RMResourceSet set, string resourceName) { + Debug.Log ($"[ResourceXferControl] RemoveSource {set.name} {resourceName}"); RemoveSet (srcSets, set, resourceName); } + public void CheckTransfer () + { + bool intersect = false; + foreach (string r in dstSets.Keys) { + if (srcSets.ContainsKey (r)) { + intersect = true; + break; + } + } + canTransfer = intersect; + } + public bool TransferResources (double deltaTime) { + if (!canTransfer) { + return false; + } bool didSomething = false; foreach (string res in dstSets.Keys) { var dst = dstSets[res]; diff --git a/Source/UI/ResourceGroup.cs b/Source/UI/ResourceGroup.cs index 1971d61f..351b4fad 100644 --- a/Source/UI/ResourceGroup.cs +++ b/Source/UI/ResourceGroup.cs @@ -73,7 +73,7 @@ public void BuildModules (RMResourceManager manager) mod.set = set; } else { Debug.Log ($"[ResourceGroup] BuildModules adding {moduleName}"); - var mod = new ResourceModule (set, resourceName); + var mod = new ResourceModule (set, resourceName, manager); moduleDict[moduleName] = mod; modules.Add (mod); } diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs index a99263fd..3fe7c7a5 100644 --- a/Source/UI/ResourceManagerView.cs +++ b/Source/UI/ResourceManagerView.cs @@ -32,35 +32,8 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public enum XferState { - Hold, - In, - Out, - }; - public class ELResourceManagerView : Layout { - /*class TransferResource : IResourceLine - { - RMResourceInfo resource; - - public string ResourceName { get { return resource.name; } } - public string ResourceInfo { get { return null; } } - public double BuildAmount { get { return resource.amount; } } - public double AvailableAmount { get { return resource.maxAmount; } } - public double ResourceFraction - { - get { - return resource.amount / resource.maxAmount; - } - } - - public TransferResource (RMResourceInfo resource) - { - this.resource = resource; - } - }*/ - ResourceGroup.List resourceGroups; ResourceGroup.Dict resourceGroupDict; ScrollView resourceView; @@ -126,7 +99,10 @@ public override void CreateUI() .Finish (); resourceGroups.Content = resourceView.Content; + } + void onTransferableChanged () + { transferButton.interactable = false; } @@ -185,6 +161,9 @@ public void SetVessel (Vessel vessel) var parts = vessel.parts; Part rootPart = parts[0].localRoot; var manager = new RMResourceManager (parts, rootPart); + manager.CreateXferControl (); + manager.xferControl.onTransferableChanged += onTransferableChanged; + onTransferableChanged (); RebuildResources (manager); } } diff --git a/Source/UI/ResourceModule.cs b/Source/UI/ResourceModule.cs index 392d0939..a48279d1 100644 --- a/Source/UI/ResourceModule.cs +++ b/Source/UI/ResourceModule.cs @@ -62,16 +62,27 @@ public double AvailableAmount #endregion public string name { get { return set.name; } } public RMResourceSet set { get; set; } - public XferState xferState { get; set; } + RMResourceManager manager; + XferState _xferState; + public XferState xferState { + get { return _xferState; } + set { + if (_xferState != value) { + manager.MoveSet (_xferState, value, set, resourceName); + } + _xferState = value; + } + } public bool flowState { get { return set.GetFlowState (resourceName); } set { set.SetFlowState (resourceName, value); } } - public ResourceModule (RMResourceSet set, string resourceName) + public ResourceModule (RMResourceSet set, string resourceName, RMResourceManager manager) { this.set = set; this.resourceName = resourceName; + this.manager = manager; xferState = XferState.Hold; } From 870774c6ea94ad9293768a49d3f6f730d6b6359e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 15:29:38 +0900 Subject: [PATCH 053/150] Fix a tab --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 8cba5fe5..f969bfa1 100644 --- a/README.txt +++ b/README.txt @@ -75,7 +75,7 @@ Note that EL depends on KodeUI: https://github.com/sarbian/KodeUI.git However, KodeUI is included as a git submodule. Use git submodule init - git submodule update + git submodule update to get started and refer to the `git submodule --help` (or https://git-scm.com/book/en/v2/Git-Tools-Submodules) for further From f44c05f5cd37c1e7c8e524018de5cbb612b96df5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 7 Oct 2020 16:48:41 +0900 Subject: [PATCH 054/150] Hook up the actual transfer Visuals are all over the place, but the functionality seems to be working nicely. --- Source/UI/ResourceManagerView.cs | 38 +++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs index 3fe7c7a5..489ddd2e 100644 --- a/Source/UI/ResourceManagerView.cs +++ b/Source/UI/ResourceManagerView.cs @@ -39,6 +39,22 @@ public class ELResourceManagerView : Layout ScrollView resourceView; UIButton transferButton; + ResourceXferControl xferControl; + bool _transferring; + bool transferring + { + get { return _transferring; } + set { + _transferring = value; + if (_transferring) { + transferButton.Text (ELLocalization.StopTransfer); + StartCoroutine (TransferResources ()); + } else { + transferButton.Text (ELLocalization.StartTransfer); + } + } + } + public override void CreateUI() { if (resourceGroups == null) { @@ -103,11 +119,21 @@ public override void CreateUI() void onTransferableChanged () { - transferButton.interactable = false; + transferButton.interactable = xferControl.canTransfer; + } + + IEnumerator TransferResources () + { + while (transferring + && xferControl.TransferResources (TimeWarp.fixedDeltaTime)) { + yield return new WaitForFixedUpdate (); + } + transferring = false; } void ToggleTransfer () { + transferring = !transferring; } void RebuildResources (RMResourceManager resourceManager) @@ -156,13 +182,19 @@ IEnumerator WaitAndRebuildResources () SetVessel (vessel); } + protected override void OnDisable () + { + transferring = false; + } + public void SetVessel (Vessel vessel) { var parts = vessel.parts; Part rootPart = parts[0].localRoot; var manager = new RMResourceManager (parts, rootPart); - manager.CreateXferControl (); - manager.xferControl.onTransferableChanged += onTransferableChanged; + xferControl = manager.CreateXferControl (); + xferControl.onTransferableChanged += onTransferableChanged; + transferring = false; onTransferableChanged (); RebuildResources (manager); } From c6dda9c4635d8a97dc5e0b2f0b5d36263c5b9bd5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 09:47:47 +0900 Subject: [PATCH 055/150] Implement the survey station view Just a site selector and rename button :) It does have some problems with seeing sites at scene load, but I think that's ELSurveyStation itself needing work (site finding etc needing a revisit: most of that hasn't changed much since the first check-in). --- Source/Makefile | 1 + Source/Survey/SurveyStation.cs | 6 +- Source/UI/Localization.cs | 3 + Source/UI/PadSurveyView.cs | 187 +++++++++++++++++++++++++++++++++ Source/UI/PadView.cs | 13 ++- 5 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 Source/UI/PadSurveyView.cs diff --git a/Source/Makefile b/Source/Makefile index 7706a0e8..4d606020 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -79,6 +79,7 @@ EL_FILES := \ UI/Localization.cs \ UI/MainWindow.cs \ UI/MiniToggle.cs \ + UI/PadSurveyView.cs \ UI/PadView.cs \ UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ diff --git a/Source/Survey/SurveyStation.cs b/Source/Survey/SurveyStation.cs index 5eb32728..0779d12b 100644 --- a/Source/Survey/SurveyStation.cs +++ b/Source/Survey/SurveyStation.cs @@ -39,8 +39,8 @@ public class ELSurveyStation : PartModule, IModuleInfo, IPartMassModifier, ELBui EL_VirtualPad virtualPad; DropDownList site_list; - List available_sites; - SurveySite site; + internal List available_sites { get; private set; } + internal SurveySite site { get; private set; } double craft_mass; [KSPField (guiName = "Range", guiActive = true)] float range = 20; @@ -164,7 +164,7 @@ public void PadSelection_start () site_list.DrawBlockingSelector (); } - void SetSite (SurveySite selected_site) + internal void SetSite (SurveySite selected_site) { if (site == selected_site) { if (site != null && virtualPad != null) { diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 08b27334..702b1a0f 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -52,6 +52,7 @@ public static class ELLocalization public static string TotalMass { get; } = "Total mass"; public static string BuildTime { get; } = "Build time"; public static string KerbalHours { get; } = "Kh"; + public static string Rename { get; } = "Rename"; public static string RenameMicropad { get; } = "Rename Micro-pad"; public static string RenameLaunchpad { get; } = "Rename Launchpad"; public static string RenameSite { get; } = "Rename Site"; @@ -64,5 +65,7 @@ public static class ELLocalization public static string Hold { get; } = "Hold"; public static string In { get; } = "In"; public static string Out { get; } = "Out"; + public static string WarningNoSite { get; } = "No sites found."; + public static string WarningNoSite2 { get; } = "No sites found. Explosions likely."; } } diff --git a/Source/UI/PadSurveyView.cs b/Source/UI/PadSurveyView.cs new file mode 100644 index 00000000..199c227a --- /dev/null +++ b/Source/UI/PadSurveyView.cs @@ -0,0 +1,187 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using TMPro; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + using OptionData = TMP_Dropdown.OptionData; + + public class ELPadSurveyView : LayoutPanel + { + ELSurveyStation surveyStation; + + Layout siteControl; + UIDropdown siteSelector; + UIButton renameSite; + UIText warningNoSite; + + List siteNames; + List siteList; + + public override void CreateUI() + { + base.CreateUI (); + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) + .Add (out siteControl) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, true) + .Add (out siteSelector, "SiteSelector") + .OnValueChanged (SelectSite) + .FlexibleLayout (true, true) + .Finish () + .Add (out renameSite) + .Text (ELLocalization.Rename) + .OnClick (RenameSite) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Add (out warningNoSite, "SiteWarning") + .Text (ELLocalization.WarningNoSite) + .Alignment (TextAlignmentOptions.Center) + .FlexibleLayout (true, true) + .SizeDelta (0, 0) + .Finish () + .Finish (); + siteNames = new List (); + siteList = new List (); + } + + void SelectSite (int index) + { + var site = siteList[index]; + surveyStation.SetSite (site); + } + + void RenameSite () + { + if (surveyStation.site != null) { + var site = surveyStation.site; + ELRenameDialog.OpenDialog (ELLocalization.RenameSite, site); + } + } + + public override void Style () + { + } + + void ShowWanring () + { + Debug.Log($"[ELPadSurveyView] ShowWanring"); + siteControl.SetActive (false); + warningNoSite.SetActive (true); + if (surveyStation.control.state == ELBuildControl.State.Complete) { + warningNoSite.Text (ELLocalization.WarningNoSite2); + } else { + warningNoSite.Text (ELLocalization.WarningNoSite); + } + } + + void ShowControl () + { + Debug.Log($"[ELPadSurveyView] ShowControl"); + siteControl.SetActive (true); + warningNoSite.SetActive (false); + } + + void BuildSiteList () + { + siteNames.Clear (); + if (surveyStation == null) { + if (gameObject.activeSelf) { + SetActive (false); + } + return; + } + if (!gameObject.activeSelf) { + SetActive (true); + } + siteList = surveyStation.available_sites; + + // FIXME make available_sites never null + if (siteList == null || siteList.Count < 1) { + ShowWanring (); + } else { + ShowControl (); + for (int i = 0; i < siteList.Count; i++) { + siteNames.Add (new OptionData (siteList[i].SiteName)); + } + siteSelector.Options (siteNames); + } + } + + IEnumerator WaitAndBuildSiteList () + { + yield return null; + BuildSiteList (); + } + + public void SetVessel (Vessel vessel) + { + BuildSiteList (); + } + + public void SetControl (ELBuildControl control) + { + surveyStation = control?.builder as ELSurveyStation; + BuildSiteList (); + } + + void onSiteRemoved (SurveySite site) + { + StartCoroutine (WaitAndBuildSiteList ()); + } + + void onSiteAdded (SurveySite site) + { + StartCoroutine (WaitAndBuildSiteList ()); + } + + protected override void OnEnable () + { + base.OnEnable (); + ELSurveyTracker.onSiteRemoved.Add (onSiteRemoved); + ELSurveyTracker.onSiteRemoved.Add (onSiteAdded); + } + + protected override void OnDisable () + { + base.OnDisable (); + ELSurveyTracker.onSiteRemoved.Remove (onSiteRemoved); + ELSurveyTracker.onSiteRemoved.Remove (onSiteAdded); + } + } +} diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index d3209a7f..38242028 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -54,6 +54,7 @@ public ELBuildControl control private set { _control = value; padEvent.Invoke (_control); + surveyView.SetControl (control); } } @@ -63,6 +64,8 @@ private set { UIDropdown padSelector; UIToggle highlightPad; + ELPadSurveyView surveyView; + protected override void Awake () { ELBuildControl.onBuildStateChanged.Add (onBuildStateChanged); @@ -128,14 +131,14 @@ public override void CreateUI() .PreferredSize (25, 25) .Finish () .Finish () - .Add () - .Horizontal () - .ControlChildSize (true, true) - .ChildForceExpand (false, false) + .Add () + .DoPreferredHeight (true) + .DoMinHeight (true) .Anchor (rightMin, rightMax) .SizeDelta (0, 0) - .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) // XXX pad / survey controls + .Add (out surveyView) + .Finish () .Finish () .Finish (); From facff05c5b1a293b631c3fea75962d4386f5a882 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 10:49:47 +0900 Subject: [PATCH 056/150] Implement the launchpad view Rotation buttons and display. Whee, other than layout tweaks, putting the build and resource managers into tabs and general styling, the UI upgrade is done. Well, that, and a lot of polish. --- Source/BuildControl.cs | 3 - Source/Makefile | 1 + Source/Pad/Launchpad.cs | 43 ++++--------- Source/UI/PadLaunchpadView.cs | 115 ++++++++++++++++++++++++++++++++++ Source/UI/PadView.cs | 5 +- 5 files changed, 132 insertions(+), 35 deletions(-) create mode 100644 Source/UI/PadLaunchpadView.cs diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index 2c49a511..060b401c 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -41,9 +41,6 @@ public interface IBuilder Transform PlaceShip (Transform shipTransform, Box vessel_bounds); void RepositionShip (Vessel ship); void PostBuild (Vessel craftVessel); - void PadSelection_start (); - void PadSelection (); - void PadSelection_end (); bool canBuild { get; } bool capture { get; } diff --git a/Source/Makefile b/Source/Makefile index 4d606020..82cdb23d 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -79,6 +79,7 @@ EL_FILES := \ UI/Localization.cs \ UI/MainWindow.cs \ UI/MiniToggle.cs \ + UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ UI/RenameDialog.cs \ diff --git a/Source/Pad/Launchpad.cs b/Source/Pad/Launchpad.cs index 3fb4a15f..e1e3bab8 100644 --- a/Source/Pad/Launchpad.cs +++ b/Source/Pad/Launchpad.cs @@ -43,7 +43,7 @@ public class ELLaunchpad : PartModule, IModuleInfo, IPartMassModifier, ELBuildCo Transform launchTransform; double craft_mass; - int rotationIndex; + public int rotationIndex { get; private set; } static Quaternion []rotations = { new Quaternion(0, 0, 0, 1), @@ -52,8 +52,6 @@ public class ELLaunchpad : PartModule, IModuleInfo, IPartMassModifier, ELBuildCo new Quaternion(0, 0.707106781f, 0, 0.707106781f), }; - static string []rotationLabels = {"12:00", "09:00", "06:00", "03:00"}; - public override string GetInfo () { return "Launchpad"; @@ -123,39 +121,22 @@ public string Name public uint ID { get { return part.flightID; } } - public void PadSelection_start () - { - } - - public void PadSelection () + public int RotateLeft () { - bool rotated = false; - - GUILayout.BeginHorizontal (); - if (GUILayout.Button ("->", ELStyles.normal, - GUILayout.ExpandWidth (false))) { - if (--rotationIndex < 0) { - rotationIndex = 3; - } - rotated = true; - } - if (GUILayout.Button ("<-", ELStyles.normal, - GUILayout.ExpandWidth (false))) { - if (++rotationIndex > 3) { - rotationIndex = 0; - } - rotated = true; - } - GUILayout.Label (rotationLabels[rotationIndex], ELStyles.normal); - GUILayout.EndHorizontal (); - - if (rotated) { - control.PlaceCraftHull (); + if (++rotationIndex > 3) { + rotationIndex = 0; } + control.PlaceCraftHull (); + return rotationIndex; } - public void PadSelection_end () + public int RotateRight () { + if (--rotationIndex < 0) { + rotationIndex = 3; + } + control.PlaceCraftHull (); + return rotationIndex; } public void Highlight (bool on) diff --git a/Source/UI/PadLaunchpadView.cs b/Source/UI/PadLaunchpadView.cs new file mode 100644 index 00000000..6adc642d --- /dev/null +++ b/Source/UI/PadLaunchpadView.cs @@ -0,0 +1,115 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using TMPro; + +using KodeUI; + +using KSP.IO; +using KSP.UI.Screens; + +namespace ExtraplanetaryLaunchpads { + + using OptionData = TMP_Dropdown.OptionData; + + public class ELPadLaunchpadView : LayoutPanel + { + ELLaunchpad launchpad; + + UIButton leftButton; + UIButton rightButton; + UIText rotationDisplay; + + static string []rotationLabels = {"12:00", "09:00", "06:00", "03:00"}; + + public override void CreateUI() + { + base.CreateUI (); + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) + .Add (out leftButton)//, "RotateLeft") FIXME + .Text ("<-") + .OnClick (RotateLeft) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Finish () + .Add (out rotationDisplay, "Rotation") + .Text ("12:00") + .Alignment (TextAlignmentOptions.Center) + .FlexibleLayout (true, true) + .Finish () + .Add (out rightButton)//, "RotateRight") FIXME + .Text ("->") + .OnClick (RotateRight) + .FlexibleLayout (false, true) + .SizeDelta (0, 0) + .Finish (); + } + + void UpdateRotationDisplay () + { + rotationDisplay.Text (rotationLabels[launchpad.rotationIndex]); + } + + void RotateLeft () + { + launchpad.RotateLeft (); + UpdateRotationDisplay (); + } + + void RotateRight () + { + launchpad.RotateRight (); + UpdateRotationDisplay (); + } + + public override void Style () + { + } + + public void SetControl (ELBuildControl control) + { + launchpad = control?.builder as ELLaunchpad; + if (launchpad != null) { + SetActive (true); + UpdateRotationDisplay (); + } else { + SetActive (false); + } + } + + protected override void OnEnable () + { + base.OnEnable (); + } + + protected override void OnDisable () + { + base.OnDisable (); + } + } +} diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 38242028..c7e75840 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -54,6 +54,7 @@ public ELBuildControl control private set { _control = value; padEvent.Invoke (_control); + launchpadView.SetControl (control); surveyView.SetControl (control); } } @@ -64,6 +65,7 @@ private set { UIDropdown padSelector; UIToggle highlightPad; + ELPadLaunchpadView launchpadView; ELPadSurveyView surveyView; protected override void Awake () @@ -136,7 +138,8 @@ public override void CreateUI() .DoMinHeight (true) .Anchor (rightMin, rightMax) .SizeDelta (0, 0) - // XXX pad / survey controls + .Add (out launchpadView) + .Finish () .Add (out surveyView) .Finish () .Finish () From ff58dfad934bab8a5154049966839d334aae39c0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 10:55:33 +0900 Subject: [PATCH 057/150] Clean out the obsolete GUI files --- Source/GUI/DropDownList.cs | 165 ----------- Source/GUI/ProgressBar.cs | 96 ------- Source/GUI/ResourceWindow.cs | 496 --------------------------------- Source/GUI/ScrollView.cs | 93 ------- Source/GUI/Styles.cs | 108 ------- Source/GUI/TextField.cs | 78 ------ Source/Makefile | 5 - Source/Survey/SurveyStation.cs | 57 ---- 8 files changed, 1098 deletions(-) delete mode 100644 Source/GUI/DropDownList.cs delete mode 100644 Source/GUI/ProgressBar.cs delete mode 100644 Source/GUI/ResourceWindow.cs delete mode 100644 Source/GUI/ScrollView.cs delete mode 100644 Source/GUI/Styles.cs delete mode 100644 Source/GUI/TextField.cs diff --git a/Source/GUI/DropDownList.cs b/Source/GUI/DropDownList.cs deleted file mode 100644 index 62af024a..00000000 --- a/Source/GUI/DropDownList.cs +++ /dev/null @@ -1,165 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using KSP; -using UnityEngine; - -namespace ExtraplanetaryLaunchpads { - - // Take from TriggerAu's plugin framework - - public class DropDownList - { - //properties to use - internal List Items { get; set; } - internal Int32 SelectedIndex { get; private set; } - internal String SelectedValue { get { return Items[SelectedIndex]; } } - - internal Boolean ListVisible; - - private Rect rectButton; - private Rect rectListBox; - - internal GUIStyle styleListItem; - internal GUIStyle styleListBox; - internal GUIStyle styleListBlocker = new GUIStyle(); - internal Int32 ListItemHeight = 20; - - //event for changes - public delegate void SelectionChangedEventHandler(Int32 OldIndex, Int32 NewIndex); - public event SelectionChangedEventHandler SelectionChanged; - - //Constructors - public DropDownList(List Items) - : this() - { - this.Items = Items; - } - public DropDownList() - { - ListVisible = false; - SelectedIndex = 0; - } - - public void SelectItem (int index) - { - if (Items == null || Items.Count < 1 || index < 0) { - index = 0; - } else if (index >= Items.Count) { - index = Items.Count - 1; - } - SelectedIndex = index; - } - - //Draw the button behind everything else to catch the first mouse click - internal void DrawBlockingSelector() - { - //do we need to draw the blocker - if (ListVisible) - { - //This will collect the click event before any other controls under the listrect - if (GUI.Button(rectListBox, "", styleListBlocker)) - { - Int32 oldIndex = SelectedIndex; - SelectedIndex = (Int32)Math.Floor((Event.current.mousePosition.y - rectListBox.y) / (rectListBox.height / Items.Count)); - //Throw an event or some such from here - if (SelectionChanged != null) { - SelectionChanged(oldIndex, SelectedIndex); - } - ListVisible = false; - } - - } - } - - //Draw the actual button for the list - internal Boolean DrawButton() - { - Boolean blnReturn = false; - //this is the dropdown button - toggle list visible if clicked - if (GUILayout.Button(SelectedValue)) - { - ListVisible = !ListVisible; - blnReturn = true; - } - //get the drawn button rectangle - if (Event.current.type == EventType.Repaint) - rectButton = GUILayoutUtility.GetLastRect(); - //draw a dropdown symbol on the right edge - Rect rectDropIcon = new Rect(rectButton) { x = (rectButton.x + rectButton.width - 20), width = 20 }; - GUI.Box(rectDropIcon, "\\/"); - - return blnReturn; - } - - //Draw the hovering dropdown - internal void DrawDropDown() - { - if (ListVisible) - { - //work out the list of items box - rectListBox = new Rect(rectButton) - { - y = rectButton.y + rectButton.height, - height = Items.Count * ListItemHeight - }; - //and draw it - GUI.Box(rectListBox, "", styleListBox); - - //now draw each listitem - for (int i = 0; i < Items.Count; i++) - { - Rect ListButtonRect = new Rect(rectListBox) { y = rectListBox.y + (i * ListItemHeight), height = 20 }; - - if (GUI.Button(ListButtonRect, Items[i], styleListItem)) - { - ListVisible = false; - SelectedIndex = i; - } - } - - //maybe put this here to limit what happens in pre/post calls - //CloseOnOutsideClick(); - } - - } - - internal Boolean CloseOnOutsideClick() - { - if (ListVisible && Event.current.type == EventType.MouseDown && !rectListBox.Contains(Event.current.mousePosition)) - { - ListVisible = false; - return true; - } - else { return false; } - } - //internal List List {get;set;} - - //internal void Add(GUIContent NewItem) { List.Add(NewItem); } - //internal void Add(String NewItem) { List.Add(new GUIContent(NewItem)); } - //internal void Add(IEnumerable NewItems) { foreach (String NewItem in NewItems) { List.Add(new GUIContent(NewItem)); } } - - //internal void Remove(GUIContent ExistingItem) { if(List.Contains(ExistingItem)) List.Remove(ExistingItem); } - - - } -} diff --git a/Source/GUI/ProgressBar.cs b/Source/GUI/ProgressBar.cs deleted file mode 100644 index f0094a7d..00000000 --- a/Source/GUI/ProgressBar.cs +++ /dev/null @@ -1,96 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KSP.IO; - -namespace ExtraplanetaryLaunchpads { - - public class ProgressBar - { - GUIStyle style_back; - GUIStyle style_bar; - GUIStyle style_bar_thin; - GUIStyle style_text; - - Texture2D ColorTexture (Color color) - { - Texture2D tex = new Texture2D (1, 1); - tex.SetPixel (0, 0, color); - tex.Apply (); - return tex; - } - - public ProgressBar (Color bar_color, Color back_color, Color text_color) - { - GUIStyle def = new GUIStyle (GUI.skin.box); - def.border = new RectOffset (2, 2, 2, 2); - def.normal.textColor = text_color; - - style_text = new GUIStyle (GUI.skin.label); - style_text.alignment = TextAnchor.MiddleCenter; - style_text.normal.textColor = text_color; - style_text.wordWrap = false; - - style_bar = new GUIStyle (def); - style_bar.normal.background = ColorTexture (bar_color); - style_bar_thin = new GUIStyle (def); - style_bar_thin.border = new RectOffset (0, 0, 0, 0); - - style_back = new GUIStyle (def); - style_back.normal.background = ColorTexture (back_color); - } - - Rect DrawBar (int width = 0) - { - List options = new List (); - if (width == 0) { - options.Add (GUILayout.ExpandWidth (true)); - } else { - options.Add (GUILayout.Width (width)); - } - GUILayout.Label ("", style_back, options.ToArray ()); - return GUILayoutUtility.GetLastRect (); - } - void DrawBarScaled (Rect rect, float scale) - { - Rect r = new Rect (rect); - r.width *= scale; - if (r.width <= 2) { - GUI.Label (r, "", style_bar_thin); - } else { - GUI.Label (r, "", style_bar); - } - } - void DrawBarText (Rect rect, string text, - TextAnchor alignment = TextAnchor.MiddleCenter) - { - style_text.alignment = alignment; - GUI.Label (rect, text, style_text); - } - public void Draw (float scale, string text, int width = 0) - { - Rect r = DrawBar (width); - DrawBarScaled (r, scale); - DrawBarText (r, text); - } - } -} diff --git a/Source/GUI/ResourceWindow.cs b/Source/GUI/ResourceWindow.cs deleted file mode 100644 index 355be9e2..00000000 --- a/Source/GUI/ResourceWindow.cs +++ /dev/null @@ -1,496 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KSP.IO; -using KSP.UI.Screens; - -using ExtraplanetaryLaunchpads_KACWrapper; - -namespace ExtraplanetaryLaunchpads { - - [KSPAddon (KSPAddon.Startup.Flight, false)] - public class ELResourceWindow : MonoBehaviour - { - static ELResourceWindow instance; - static bool hide_ui = false; - static bool gui_enabled = false; - static Rect windowpos; - static bool link_lfo_sliders = true; - static ELScrollView resscroll = new ELScrollView (680, 300); - static GUILayoutOption toggleWidth = GUILayout.Width (80); - - public enum XferState { - Hold, - In, - Out, - }; - - RMResourceManager resourceManager; - bool []setSelected; - XferState []xferState; - Dictionary dstSets; - Dictionary srcSets; - bool canTransfer; - List resources; - bool []resourceStates; - bool resourceStatesChanged; - bool transferring; - - internal void Start() - { - } - - public static void ToggleGUI () - { - gui_enabled = !gui_enabled; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void HideGUI () - { - gui_enabled = false; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void ShowGUI () - { - gui_enabled = true; - if (instance != null) { - instance.UpdateGUIState (); - } - } - - public static void LoadSettings (ConfigNode node) - { - string val = node.GetValue ("rect"); - if (val != null) { - Quaternion pos; - pos = ConfigNode.ParseQuaternion (val); - windowpos.x = pos.x; - windowpos.y = pos.y; - windowpos.width = pos.z; - windowpos.height = pos.w; - } - val = node.GetValue ("visible"); - if (val != null) { - bool.TryParse (val, out gui_enabled); - } - val = node.GetValue ("link_lfo_sliders"); - if (val != null) { - bool.TryParse (val, out link_lfo_sliders); - } - } - - public static void SaveSettings (ConfigNode node) - { - Quaternion pos; - pos.x = windowpos.x; - pos.y = windowpos.y; - pos.z = windowpos.width; - pos.w = windowpos.height; - node.AddValue ("rect", KSPUtil.WriteQuaternion (pos)); - node.AddValue ("visible", gui_enabled); - node.AddValue ("link_lfo_sliders", link_lfo_sliders); - } - - void RebuildSets (Vessel v) - { - Part rootPart = v.parts[0].localRoot; - //Debug.Log ($"[ELResourceWindow] RebuildSets"); - resourceManager = new RMResourceManager (v.parts, rootPart, - true, true); - resscroll.Reset (); - var set = new HashSet (); - setSelected = null; - xferState = null; - dstSets.Clear (); - srcSets.Clear (); - foreach (var s in resourceManager.resourceSets) { - foreach (string r in s.resources.Keys) { - set.Add (r); - } - } - resources = set.ToList (); - resourceStates = new bool [resources.Count]; - - UpdateGUIState (); - } - - IEnumerator WaitAndRebuildSets (Vessel v) - { - for (int i = 5; i-- > 0; ) { - yield return null; - } - if (!v) { - yield break; - } - RebuildSets (v); - } - - void onVesselChange (Vessel v) - { - StartCoroutine (WaitAndRebuildSets (v)); - } - - void onVesselWasModified (Vessel v) - { - if (FlightGlobals.ActiveVessel == v) { - StartCoroutine (WaitAndRebuildSets (v)); - } - } - - void OnLinkCreated (KAS.IKasLinkEvent evt) - { - if (evt.source.part.vessel == FlightGlobals.ActiveVessel - || evt.target.part.vessel == FlightGlobals.ActiveVessel) { - StartCoroutine (WaitAndRebuildSets (FlightGlobals.ActiveVessel)); - } - } - - void OnLinkBroken (KAS.IKasLinkEvent evt) - { - if (evt.source.part.vessel == FlightGlobals.ActiveVessel - || evt.target.part.vessel == FlightGlobals.ActiveVessel) { - StartCoroutine (WaitAndRebuildSets (FlightGlobals.ActiveVessel)); - } - } - - void UpdateGUIState () - { - enabled = !hide_ui && resourceManager != null && gui_enabled; - } - - void onHideUI () - { - hide_ui = true; - UpdateGUIState (); - } - - void onShowUI () - { - hide_ui = false; - UpdateGUIState (); - } - - void Awake () - { - instance = this; - GameEvents.onVesselChange.Add (onVesselChange); - GameEvents.onVesselWasModified.Add (onVesselWasModified); - KAS.IKasEvents.OnLinkCreated.Add (OnLinkCreated); - KAS.IKasEvents.OnLinkBroken.Add (OnLinkBroken); - GameEvents.onHideUI.Add (onHideUI); - GameEvents.onShowUI.Add (onShowUI); - enabled = false; - - dstSets = new Dictionary (); - srcSets = new Dictionary (); - } - - void OnDestroy () - { - instance = null; - GameEvents.onVesselChange.Remove (onVesselChange); - GameEvents.onVesselWasModified.Remove (onVesselWasModified); - KAS.IKasEvents.OnLinkCreated.Remove (OnLinkCreated); - KAS.IKasEvents.OnLinkBroken.Remove (OnLinkBroken); - GameEvents.onHideUI.Remove (onHideUI); - GameEvents.onShowUI.Remove (onShowUI); - } - - IEnumerator TransferResources () - { - while (transferring) { - bool didSomething = false; - foreach (string res in dstSets.Keys) { - var dst = dstSets[res]; - if (!srcSets.ContainsKey (res)) { - continue; - } - var src = srcSets[res]; - double amount = dst.ResourceCapacity (res) / 20; - amount *= Time.deltaTime; - double srem = src.TransferResource (res, -amount); - // srem (amount not pulled) will be negative - if (srem == -amount) { - // could not pull any - continue; - } - amount += srem; - double drem = dst.TransferResource (res, amount); - if (drem != amount) { - didSomething = true; - } - // return any untransfered amount back to source - src.TransferResource (res, drem); - } - if (!didSomething) { - transferring = false; - break; - } - yield return new WaitForFixedUpdate (); - } - } - - void TransferButtons () - { - bool gui_enabled = GUI.enabled; - - GUI.enabled = canTransfer; - if (transferring) { - if (GUILayout.Button ("Stop Transfer")) { - transferring = false; - } - } else { - if (GUILayout.Button ("Start Transfer")) { - transferring = true; - StartCoroutine (TransferResources ()); - } - } - GUI.enabled = gui_enabled; - } - - void CloseButton () - { - GUILayout.BeginHorizontal (); - GUILayout.FlexibleSpace (); - if (GUILayout.Button ("Close")) { - HideGUI (); - } - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - } - - bool ResourceLine (int ind) - { - string res = resources[ind]; - bool state = resourceStates[ind]; - GUILayout.BeginHorizontal (); - resourceStates[ind] = GUILayout.Toggle (state, res); - if (state != resourceStates[ind]) { - resourceStatesChanged = true; - } - GUILayout.FlexibleSpace (); - GUILayout.EndHorizontal (); - return state; - } - - void HighlightPart (Part part, bool on) - { - if (on) { - part.SetHighlightColor (XKCDColors.LightSeaGreen); - part.SetHighlight (true, false); - } else { - part.SetHighlightDefault (); - } - } - - void HighlightSet (RMResourceSet set, string res, bool on) - { - RMResourceInfo info; - if (set.resources.TryGetValue (res, out info)) { - for (int i = 0; i < info.containers.Count; i++) { - var c = info.containers[i]; - if (c is PartResourceContainer) { - HighlightPart (c.part, on); - } else if (c is ResourceSetContainer) { - var sc = c as ResourceSetContainer; - HighlightSet (sc.set, res, on); - } - } - } - } - - void ToggleXferState (int ind, XferState state, string label) - { - bool on = false; - if (xferState != null) { - on = xferState[ind] == state; - } - if (GUILayout.Toggle (on, label, toggleWidth)) { - if (xferState != null) { - xferState[ind] = state; - } - } - } - - void RemoveSet (Dictionary dict, RMResourceSet set, string res) - { - var s = dict[res]; - s.RemoveSet (set); - if (s.resources.Count < 1) { - dict.Remove (res); - } - } - - void AddSet (Dictionary dict, RMResourceSet set, string res) - { - if (!dict.ContainsKey (res)) { - dict[res] = new RMResourceSet (); - dict[res].balanced = true; - } - dict[res].AddSet (set); - } - - void TransferState (int ind, RMResourceSet set, string res) - { - XferState old = XferState.Hold; - if (xferState != null) { - old = xferState[ind]; - } - ToggleXferState (ind, XferState.Hold, "Hold"); - ToggleXferState (ind, XferState.In, "In"); - ToggleXferState (ind, XferState.Out, "Out"); - GUILayout.Space (40); - if (xferState != null && xferState[ind] != old) { - if (old == XferState.In) { - RemoveSet (dstSets, set, res); - } else if (old == XferState.Out) { - RemoveSet (srcSets, set, res); - } - if (xferState[ind] == XferState.In) { - AddSet (dstSets, set, res); - } else if (xferState[ind] == XferState.Out) { - AddSet (srcSets, set, res); - } - canTransfer = false; - foreach (string r in dstSets.Keys) { - if (srcSets.ContainsKey (r)) { - canTransfer = true; - break; - } - } - } - } - - void FlowState (RMResourceSet set, string res) - { - bool curFlow = set.GetFlowState (res); - bool newFlow = GUILayout.Toggle (curFlow, ""); - if (newFlow != curFlow) { - set.SetFlowState (res, newFlow); - } - } - - void ModuleResourceLine (int ind, RMResourceSet set, string res, - bool highlight) - { - double amount = set.ResourceAmount (res); - double maxAmount = set.ResourceCapacity (res); - GUILayout.BeginHorizontal (); - GUILayout.Space (40); - GUILayout.Label (set.name, ELStyles.label); - GUILayout.FlexibleSpace (); - string amountFmt = "F0"; - string maxAmountFmt = "F0"; - if (amount < 100) { - amountFmt = "F2"; - } - if (maxAmount < 100) { - maxAmountFmt = "F2"; - } - GUILayout.Label (amount.ToString(amountFmt), ELStyles.label); - GUILayout.Label ("/", ELStyles.label); - GUILayout.Label (maxAmount.ToString(maxAmountFmt), ELStyles.label); - TransferState (ind, set, res); - FlowState (set, res); - GUILayout.EndHorizontal (); - - if (setSelected != null - && Event.current.type == EventType.Repaint) { - var rect = GUILayoutUtility.GetLastRect(); - if (highlight && rect.Contains(Event.current.mousePosition)) { - if (!setSelected[ind]) { - setSelected[ind] = true; - HighlightSet (set, res, true); - } - } else { - if (setSelected[ind]) { - setSelected[ind] = false; - HighlightSet (set, res, false); - } - } - } - } - - void ResourceModules (bool highlight) - { - int ind = 0; - for (int i = 0; i < resources.Count; i++) { - string res = resources[i]; - if (ResourceLine (i)) { - for (int j = 0; j < resourceManager.resourceSets.Count; j++) { - var set = resourceManager.resourceSets[j]; - if (!set.resources.ContainsKey (res)) { - continue; - } - ModuleResourceLine (ind++, set, res, highlight); - } - } - } - if (resourceStatesChanged) { - resourceStatesChanged = false; - setSelected = null; - xferState = null; - } else { - if (setSelected == null && ind > 0) { - setSelected = new bool[ind]; - xferState = new XferState[ind]; - } - } - } - - void WindowGUI (int windowID) - { - ELStyles.Init (); - - GUILayout.BeginVertical (); - - resscroll.Begin (); - ResourceModules (resscroll.mouseOver); - resscroll.End (); - - GUILayout.EndVertical (); - - TransferButtons (); - CloseButton (); - - GUI.DragWindow (new Rect (0, 0, 10000, 20)); - - } - - void OnGUI () - { - GUI.skin = HighLogic.Skin; - windowpos = GUILayout.Window (GetInstanceID (), - windowpos, WindowGUI, - ELVersionReport.GetVersion (), - GUILayout.Width (695)); - } - } -} diff --git a/Source/GUI/ScrollView.cs b/Source/GUI/ScrollView.cs deleted file mode 100644 index 94ce3c79..00000000 --- a/Source/GUI/ScrollView.cs +++ /dev/null @@ -1,93 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using UnityEngine; - -namespace ExtraplanetaryLaunchpads { - - public class ELScrollView - { - public delegate void ScrollFunc (); - public ScrollFunc Begin { get; private set; } - public ScrollFunc End { get; private set; } - - Rect rect; - public Vector2 scroll; - public bool mouseOver { get; private set; } - GUILayoutOption width; - GUILayoutOption height; - - public ELScrollView (int width, int height) - { - this.width = GUILayout.Width (width); - this.height = GUILayout.Height (height); - - Begin = BeginWidthHeight; - End = EndWidthHeight; - } - - public ELScrollView (int height) - { - this.height = GUILayout.Height (height); - - Begin = BeginHeight; - End = EndHeight; - } - - void BeginWidthHeight () - { - scroll = GUILayout.BeginScrollView (scroll, width, height); - GUILayout.BeginHorizontal (); - GUILayout.BeginVertical (); - } - - void BeginHeight () - { - scroll = GUILayout.BeginScrollView (scroll, height); - GUILayout.BeginVertical (); - } - - void EndWidthHeight () - { - GUILayout.EndVertical (); - GUILayout.Space (15); - GUILayout.EndHorizontal (); - GUILayout.EndScrollView (); - if (Event.current.type == EventType.Repaint) { - rect = GUILayoutUtility.GetLastRect(); - mouseOver = rect.Contains(Event.current.mousePosition); - } - } - - void EndHeight () - { - GUILayout.EndVertical (); - GUILayout.EndScrollView (); - if (Event.current.type == EventType.Repaint) { - rect = GUILayoutUtility.GetLastRect(); - mouseOver = rect.Contains(Event.current.mousePosition); - } - } - - public void Reset () - { - scroll = Vector2.zero; - } - } - -} diff --git a/Source/GUI/Styles.cs b/Source/GUI/Styles.cs deleted file mode 100644 index 55c01651..00000000 --- a/Source/GUI/Styles.cs +++ /dev/null @@ -1,108 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KSP.IO; -using KSP.UI.Screens; - -using ExtraplanetaryLaunchpads_KACWrapper; - -namespace ExtraplanetaryLaunchpads { - - public class ELStyles { - public static GUIStyle normal; - public static GUIStyle red; - public static GUIStyle yellow; - public static GUIStyle green; - public static GUIStyle white; - public static GUIStyle label; - public static GUIStyle slider; - public static GUIStyle sliderText; - - public static GUIStyle listItem; - public static GUIStyle listBox; - - public static ProgressBar bar; - - private static bool initialized; - - public static void Init () - { - if (initialized) - return; - initialized = true; - - normal = new GUIStyle (GUI.skin.button); - normal.normal.textColor = normal.focused.textColor = Color.white; - normal.hover.textColor = normal.active.textColor = Color.yellow; - normal.onNormal.textColor = normal.onFocused.textColor = normal.onHover.textColor = normal.onActive.textColor = Color.green; - normal.padding = new RectOffset (8, 8, 8, 8); - - red = new GUIStyle (GUI.skin.box); - red.padding = new RectOffset (8, 8, 8, 8); - red.normal.textColor = red.focused.textColor = Color.red; - - yellow = new GUIStyle (GUI.skin.box); - yellow.padding = new RectOffset (8, 8, 8, 8); - yellow.normal.textColor = yellow.focused.textColor = Color.yellow; - - green = new GUIStyle (GUI.skin.box); - green.padding = new RectOffset (8, 8, 8, 8); - green.normal.textColor = green.focused.textColor = Color.green; - green.wordWrap = false; - - white = new GUIStyle (GUI.skin.box); - white.padding = new RectOffset (8, 8, 8, 8); - white.normal.textColor = white.focused.textColor = Color.white; - white.wordWrap = false; - - label = new GUIStyle (GUI.skin.label); - label.normal.textColor = label.focused.textColor = Color.white; - label.alignment = TextAnchor.MiddleCenter; - label.wordWrap = false; - - slider = new GUIStyle (GUI.skin.horizontalSlider); - slider.margin = new RectOffset (0, 0, 0, 0); - - sliderText = new GUIStyle (GUI.skin.label); - sliderText.alignment = TextAnchor.MiddleCenter; - sliderText.margin = new RectOffset (0, 0, 0, 0); - - listItem = new GUIStyle (); - listItem.normal.textColor = Color.white; - Texture2D texInit = new Texture2D(1, 1); - texInit.SetPixel(0, 0, Color.white); - texInit.Apply(); - listItem.hover.background = texInit; - listItem.onHover.background = texInit; - listItem.hover.textColor = Color.black; - listItem.onHover.textColor = Color.black; - listItem.padding = new RectOffset(4, 4, 4, 4); - - listBox = new GUIStyle(GUI.skin.box); - - bar = new ProgressBar (XKCDColors.Azure, - XKCDColors.ElectricBlue, - new Color(255, 255, 255, 0.8f)); - } - } -} diff --git a/Source/GUI/TextField.cs b/Source/GUI/TextField.cs deleted file mode 100644 index 08a128e8..00000000 --- a/Source/GUI/TextField.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using UnityEngine; - -namespace ExtraplanetaryLaunchpads { - - public class TextField - { - string controlName; - - string newText; - string _text; - public string text - { - get { return _text; } - set { _text = value; newText = value; } - } - - bool resetOnFocusLoss; - - public TextField (string controlName, bool reset = false) - { - this.controlName = controlName; - resetOnFocusLoss = reset; - } - - public void AcceptInput () - { - text = newText; - } - - public bool HandleInput () - { - bool done = false; - - GUI.SetNextControlName (controlName); - if (GUI.GetNameOfFocusedControl () == controlName) { - if (Event.current.isKey) { - switch (Event.current.keyCode) { - case KeyCode.Return: - case KeyCode.KeypadEnter: - Event.current.Use (); - done = true; - AcceptInput (); - break; - case KeyCode.Escape: - newText = text; - done = true; - break; - } - } - } else { - if (resetOnFocusLoss) { - newText = text; - } - } - newText = GUILayout.TextField (newText); - return done; - } - } - -} diff --git a/Source/Makefile b/Source/Makefile index 82cdb23d..b58b4b0a 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -61,12 +61,7 @@ EL_FILES := \ assembly/Checkers.cs \ assembly/VersionReport.cs \ GUI/CraftBrowser.cs \ - GUI/DropDownList.cs \ GUI/EditorToolbar.cs \ - GUI/ProgressBar.cs \ - GUI/ScrollView.cs \ - GUI/Styles.cs \ - GUI/TextField.cs \ LaunchClamp/LaunchClamp.cs \ Pad/Launchpad.cs \ Recycler/Recycler.cs \ diff --git a/Source/Survey/SurveyStation.cs b/Source/Survey/SurveyStation.cs index 0779d12b..478d2591 100644 --- a/Source/Survey/SurveyStation.cs +++ b/Source/Survey/SurveyStation.cs @@ -38,7 +38,6 @@ public class ELSurveyStation : PartModule, IModuleInfo, IPartMassModifier, ELBui [KSPField] public float EVARange = 0; EL_VirtualPad virtualPad; - DropDownList site_list; internal List available_sites { get; private set; } internal SurveySite site { get; private set; } double craft_mass; @@ -154,16 +153,6 @@ public bool canOperate } } - public void PadSelection_start () - { - if (site_list == null) { - return; - } - site_list.styleListItem = ELStyles.listItem; - site_list.styleListBox = ELStyles.listBox; - site_list.DrawBlockingSelector (); - } - internal void SetSite (SurveySite selected_site) { if (site == selected_site) { @@ -188,54 +177,10 @@ internal void SetSite (SurveySite selected_site) virtualPad.SetSite (site); } } - if (site_list != null) { - site_list.SelectItem (available_sites.IndexOf (site)); - } control.PlaceCraftHull (); // The build window will take care of turning on highlighting } - void RenameSite () - { - bool en = GUI.enabled; - GUI.enabled = en && (site != null); - if (GUILayout.Button ("Rename Site", ELStyles.normal, - GUILayout.ExpandWidth (false))) { - if (site != null) { - ELRenameDialog.OpenDialog (ELLocalization.RenameSite, site); - } - } - GUI.enabled = en; - } - - public void PadSelection () - { - if (site_list == null) { - GUILayout.BeginHorizontal (); - if (control.state == ELBuildControl.State.Complete) { - GUILayout.Label ("No sites found. Explosions likely.", - ELStyles.red); - } else { - GUILayout.Label ("No sites found."); - } - GUILayout.EndHorizontal (); - } else { - GUILayout.BeginHorizontal (); - site_list.DrawButton (); - SetSite (available_sites[site_list.SelectedIndex]); - RenameSite (); - GUILayout.EndHorizontal (); - } - } - - public void PadSelection_end () - { - if (site_list != null) { - site_list.DrawDropDown(); - site_list.CloseOnOutsideClick(); - } - } - public void Highlight (bool on) { if (on) { @@ -414,7 +359,6 @@ void FindSites () available_sites = ELSurveyTracker.instance.FindSites (vessel, range); if (available_sites == null || available_sites.Count < 1) { Highlight (false); - site_list = null; SetSite (null); } else { var slist = new List (); @@ -425,7 +369,6 @@ void FindSites () Highlight (false); SetSite (available_sites[0]); } - site_list = new DropDownList (slist); } } From 3b6deb75f1724aac0f79cfaa975015bc14e3e500 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 11:23:42 +0900 Subject: [PATCH 058/150] Clean up unused usings in UI --- Source/UI/BuildManagerView.cs | 13 ------------- Source/UI/BuildView.cs | 7 ------- Source/UI/CraftView.cs | 4 +--- Source/UI/IResourceLine.cs | 7 ------- Source/UI/Localization.cs | 10 ---------- Source/UI/MainWindow.cs | 9 --------- Source/UI/MiniToggle.cs | 2 -- Source/UI/PadLaunchpadView.cs | 10 ---------- Source/UI/PadSurveyView.cs | 5 ----- Source/UI/PadView.cs | 5 ----- Source/UI/RenameDialog.cs | 6 ------ Source/UI/ResourceDisplay.cs | 8 -------- Source/UI/ResourceGroup.cs | 10 ---------- Source/UI/ResourceGroupView.cs | 13 ------------- Source/UI/ResourceLine.cs | 1 - Source/UI/ResourceManagerView.cs | 8 -------- Source/UI/ResourceModule.cs | 10 ---------- Source/UI/ResourceModuleView.cs | 10 ---------- Source/UI/ShipInfo.cs | 3 --- Source/UI/ShipInfoWindow.cs | 2 -- Source/UI/StatusBar.cs | 7 ------- Source/UI/TextInfoLine.cs | 2 -- Source/UI/ToggleText.cs | 1 - Source/UI/TransferView.cs | 7 ------- Source/UI/WindowManager.cs | 7 ------- 25 files changed, 1 insertion(+), 166 deletions(-) diff --git a/Source/UI/BuildManagerView.cs b/Source/UI/BuildManagerView.cs index 69401982..2bc3e18a 100644 --- a/Source/UI/BuildManagerView.cs +++ b/Source/UI/BuildManagerView.cs @@ -15,21 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using TMPro; - using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELBuildManagerView : Layout diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index 76bd0a69..fbb983eb 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -15,21 +15,14 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELBuildView : Layout diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index f8b6e6c5..c2957ba5 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -17,17 +17,15 @@ You should have received a copy of the GNU General Public License */ using System; using System.IO; -using System.Reflection; using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.UI; using TMPro; using KodeUI; -using KSP.IO; +//using KSP.IO; using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; namespace ExtraplanetaryLaunchpads { diff --git a/Source/UI/IResourceLine.cs b/Source/UI/IResourceLine.cs index e717d95d..07114f2f 100644 --- a/Source/UI/IResourceLine.cs +++ b/Source/UI/IResourceLine.cs @@ -15,13 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.UI; -using TMPro; - -using KodeUI; namespace ExtraplanetaryLaunchpads { diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 702b1a0f..c87ea281 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -15,16 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - -using KodeUI; - -using KSP.IO; -using KSP.UI.Screens; namespace ExtraplanetaryLaunchpads { diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index bab5bf1c..3107ca3f 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -15,17 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; - using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - namespace ExtraplanetaryLaunchpads { public class ELMainWindow : Window diff --git a/Source/UI/MiniToggle.cs b/Source/UI/MiniToggle.cs index 3cca5dd9..3502b18b 100644 --- a/Source/UI/MiniToggle.cs +++ b/Source/UI/MiniToggle.cs @@ -15,11 +15,9 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; -using TMPro; using KodeUI; diff --git a/Source/UI/PadLaunchpadView.cs b/Source/UI/PadLaunchpadView.cs index 6adc642d..925c3b41 100644 --- a/Source/UI/PadLaunchpadView.cs +++ b/Source/UI/PadLaunchpadView.cs @@ -15,22 +15,12 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; -using UnityEngine.Events; using TMPro; using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - namespace ExtraplanetaryLaunchpads { - using OptionData = TMP_Dropdown.OptionData; - public class ELPadLaunchpadView : LayoutPanel { ELLaunchpad launchpad; diff --git a/Source/UI/PadSurveyView.cs b/Source/UI/PadSurveyView.cs index 199c227a..445ed748 100644 --- a/Source/UI/PadSurveyView.cs +++ b/Source/UI/PadSurveyView.cs @@ -15,18 +15,13 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using System.Collections; using System.Collections.Generic; using UnityEngine; -using UnityEngine.Events; using TMPro; using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - namespace ExtraplanetaryLaunchpads { using OptionData = TMP_Dropdown.OptionData; diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index c7e75840..9507aa89 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -16,18 +16,13 @@ You should have received a copy of the GNU General Public License . */ using System; -using System.Reflection; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.Events; using TMPro; using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - namespace ExtraplanetaryLaunchpads { using OptionData = TMP_Dropdown.OptionData; diff --git a/Source/UI/RenameDialog.cs b/Source/UI/RenameDialog.cs index 79feefe1..553ebb03 100644 --- a/Source/UI/RenameDialog.cs +++ b/Source/UI/RenameDialog.cs @@ -15,12 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; using TMPro; using KodeUI; diff --git a/Source/UI/ResourceDisplay.cs b/Source/UI/ResourceDisplay.cs index b8598a47..aace1559 100644 --- a/Source/UI/ResourceDisplay.cs +++ b/Source/UI/ResourceDisplay.cs @@ -15,15 +15,7 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using TMPro; using KodeUI; diff --git a/Source/UI/ResourceGroup.cs b/Source/UI/ResourceGroup.cs index 351b4fad..176b0c36 100644 --- a/Source/UI/ResourceGroup.cs +++ b/Source/UI/ResourceGroup.cs @@ -15,21 +15,11 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEngine; -using UnityEngine.UI; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ResourceGroup : IResourceLine diff --git a/Source/UI/ResourceGroupView.cs b/Source/UI/ResourceGroupView.cs index cde64c42..09637b5e 100644 --- a/Source/UI/ResourceGroupView.cs +++ b/Source/UI/ResourceGroupView.cs @@ -15,21 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using TMPro; - using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELResourceGroupView : Layout diff --git a/Source/UI/ResourceLine.cs b/Source/UI/ResourceLine.cs index fb2ced8e..1bfafa17 100644 --- a/Source/UI/ResourceLine.cs +++ b/Source/UI/ResourceLine.cs @@ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License . */ using System; -using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs index 489ddd2e..12521f1d 100644 --- a/Source/UI/ResourceManagerView.cs +++ b/Source/UI/ResourceManagerView.cs @@ -15,21 +15,13 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.UI; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELResourceManagerView : Layout diff --git a/Source/UI/ResourceModule.cs b/Source/UI/ResourceModule.cs index a48279d1..1dba298e 100644 --- a/Source/UI/ResourceModule.cs +++ b/Source/UI/ResourceModule.cs @@ -15,21 +15,11 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; using System.Collections.Generic; -using System.Linq; using UnityEngine; -using UnityEngine.UI; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ResourceModule : IResourceLine diff --git a/Source/UI/ResourceModuleView.cs b/Source/UI/ResourceModuleView.cs index bcafcf98..589d8f73 100644 --- a/Source/UI/ResourceModuleView.cs +++ b/Source/UI/ResourceModuleView.cs @@ -15,22 +15,12 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; -using System.Collections; -using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELResourceModuleView : Layout, IPointerEnterHandler, IPointerExitHandler diff --git a/Source/UI/ShipInfo.cs b/Source/UI/ShipInfo.cs index 6d7e2dbf..720cf4b5 100644 --- a/Source/UI/ShipInfo.cs +++ b/Source/UI/ShipInfo.cs @@ -15,10 +15,7 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using System.Collections; -using System.Collections.Generic; -using System.Linq; using UnityEngine; using KSP.UI.Screens; diff --git a/Source/UI/ShipInfoWindow.cs b/Source/UI/ShipInfoWindow.cs index 61f263bf..4b78105c 100644 --- a/Source/UI/ShipInfoWindow.cs +++ b/Source/UI/ShipInfoWindow.cs @@ -16,9 +16,7 @@ You should have received a copy of the GNU General Public License . */ using System; -using System.Reflection; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.UI; diff --git a/Source/UI/StatusBar.cs b/Source/UI/StatusBar.cs index a491db47..3780b4e0 100644 --- a/Source/UI/StatusBar.cs +++ b/Source/UI/StatusBar.cs @@ -15,18 +15,11 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; using UnityEngine; using TMPro; using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - namespace ExtraplanetaryLaunchpads { public class ELStatusBar : Layout diff --git a/Source/UI/TextInfoLine.cs b/Source/UI/TextInfoLine.cs index f07406fd..2ee5f797 100644 --- a/Source/UI/TextInfoLine.cs +++ b/Source/UI/TextInfoLine.cs @@ -15,8 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; diff --git a/Source/UI/ToggleText.cs b/Source/UI/ToggleText.cs index 59404d69..0cd5eda0 100644 --- a/Source/UI/ToggleText.cs +++ b/Source/UI/ToggleText.cs @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; diff --git a/Source/UI/TransferView.cs b/Source/UI/TransferView.cs index ec065e0d..0a99111b 100644 --- a/Source/UI/TransferView.cs +++ b/Source/UI/TransferView.cs @@ -15,21 +15,14 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; -using TMPro; using KodeUI; -using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELTransferView : Layout diff --git a/Source/UI/WindowManager.cs b/Source/UI/WindowManager.cs index 2a4a9372..77490d51 100644 --- a/Source/UI/WindowManager.cs +++ b/Source/UI/WindowManager.cs @@ -15,17 +15,10 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; using UnityEngine; using KodeUI; -using KSP.IO; -using KSP.UI.Screens; - using ExtraplanetaryLaunchpads_KACWrapper; namespace ExtraplanetaryLaunchpads { From e80ac9af0ef15953392d954aec243f6c5bc49912 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 13:19:13 +0900 Subject: [PATCH 059/150] Fix a missed localization in UI --- Source/UI/RenameDialog.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UI/RenameDialog.cs b/Source/UI/RenameDialog.cs index 553ebb03..c58f3268 100644 --- a/Source/UI/RenameDialog.cs +++ b/Source/UI/RenameDialog.cs @@ -39,7 +39,7 @@ public override void CreateUI() { base.CreateUI (); - this.Title ("Rename") + this.Title (ELLocalization.Rename) .Vertical() .ControlChildSize (true, true) .ChildForceExpand (false,false) From 2b6c7c5c31192c9b877ec47ded6265977c872829 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 14:16:59 +0900 Subject: [PATCH 060/150] Document EL_ResourceLink --- Documentation/EL_Manual.lyx | 158 ++++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/Documentation/EL_Manual.lyx b/Documentation/EL_Manual.lyx index 01460171..981084eb 100644 --- a/Documentation/EL_Manual.lyx +++ b/Documentation/EL_Manual.lyx @@ -6809,26 +6809,32 @@ Resources \end_layout \begin_layout Verbatim + EL_Recipe { \end_layout \begin_layout Verbatim + structure = 5 \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -6927,30 +6933,37 @@ literal "true" \end_layout \begin_layout Verbatim + EL_ModuleRecipe { \end_layout \begin_layout Verbatim + name = KerbalEVA \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + Metal = 39 \end_layout \begin_layout Verbatim + loss = 44.75 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -6975,14 +6988,17 @@ EL_DefaultStructureRecipe \begin_deeper \begin_layout Verbatim + EL_DefaultStructureRecipe { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout @@ -7110,26 +7126,32 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_ResourceRecipe { \end_layout \begin_layout Verbatim + name = Ablator \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7408,30 +7430,37 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_RecycleRecipe { \end_layout \begin_layout Verbatim + name = RocketParts \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + ScrapMetal = 9 \end_layout \begin_layout Verbatim + loss = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7516,26 +7545,32 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_TransferRecipe { \end_layout \begin_layout Verbatim + name = RocketParts \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + RocketParts = 1 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7620,34 +7655,42 @@ literal "true" \begin_deeper \begin_layout Verbatim + EL_KerbalRecipe { \end_layout \begin_layout Verbatim + structure = 10 \end_layout \begin_layout Verbatim + KerbalEVA = 83.75 \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + Kethane = 30 \end_layout \begin_layout Verbatim + loss = -29 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7748,110 +7791,137 @@ efficiency \end_layout \begin_layout Verbatim + EL_ConverterRecipe { \end_layout \begin_layout Verbatim + name = LFOFiredSmelter \end_layout \begin_layout Verbatim + Input { \end_layout \begin_layout Verbatim + efficiency = 1 \end_layout \begin_layout Verbatim + LFOMix = 864.49048 -5186.94288 \end_layout \begin_layout Verbatim + MetalOre = 1596.882 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Output { \end_layout \begin_layout Verbatim + efficiency = 1 \end_layout \begin_layout Verbatim + CarbonDioxide = 1056.228 \end_layout \begin_layout Verbatim + Water = 288.24448 \end_layout \begin_layout Verbatim + Metal = 1116.9 -9627.678 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Input { \end_layout \begin_layout Verbatim + efficiency = 0 \end_layout \begin_layout Verbatim + LFOMix = 864.49048 -5186.94288 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + Output { \end_layout \begin_layout Verbatim + efficiency = 0 \end_layout \begin_layout Verbatim + Carbon = 24.0214 \end_layout \begin_layout Verbatim + CarbonDioxide = 176.038 \end_layout \begin_layout Verbatim + CarbonMonoxide = 476.1717 \end_layout \begin_layout Verbatim + Formaldehyde = 30.02598 \end_layout \begin_layout Verbatim + Hydrogen = 14.11116 \end_layout \begin_layout Verbatim + Water = 144.12224 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout @@ -7860,34 +7930,113 @@ EL_ConverterRecipe { \end_layout \begin_layout Verbatim + EL_ResourceRecipe { \end_layout \begin_layout Verbatim + name = LFOMix \end_layout \begin_layout Verbatim + Resources { \end_layout \begin_layout Verbatim + LiquidFuel = 9 \end_layout \begin_layout Verbatim + Oxidizer = 11 \end_layout \begin_layout Verbatim + } \end_layout \begin_layout Verbatim + } \end_layout \end_deeper +\begin_layout Subsubsection +Other Recipes +\end_layout + +\begin_layout Description +EL_ResourceLink While not strictly a recipe, +\noun on +EL_ResourceLink +\noun default + is used for specifying resources that should be linked when setting up + resource transfer after building a new craft but before releasing it. + The node is very simple: a +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +name +\end_layout + +\end_inset + + line that names the link set (currently not used internally, but useful + for Module Manager patches), and a series of +\begin_inset Flex Code +status open + +\begin_layout Plain Layout +resource +\end_layout + +\end_inset + + lines that specify the resources in the link set. + Any link sets with overlaps in their linked resources will result in undefined + behavior +\begin_inset Foot +status collapsed + +\begin_layout Plain Layout +rhinodamons +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Verbatim + +EL_ResourceLink { +\end_layout + +\begin_layout Verbatim + + name = RocketFuel +\end_layout + +\begin_layout Verbatim + + resource = LiquidFuel +\end_layout + +\begin_layout Verbatim + + resource = Oxidizer +\end_layout + +\begin_layout Verbatim + +} +\end_layout + \begin_layout Subsection Resource Rates \end_layout @@ -7966,38 +8115,47 @@ default \end_layout \begin_layout Verbatim + EL_ResourceRates { \end_layout \begin_layout Verbatim + default = 5 \end_layout \begin_layout Verbatim + ElectricCharge = 1 \end_layout \begin_layout Verbatim + LiquidFuel = 0.36 \end_layout \begin_layout Verbatim + Oxidizer = 0.44 \end_layout \begin_layout Verbatim + MonoPropellant = 0.4 \end_layout \begin_layout Verbatim + XenonGas = 2 \end_layout \begin_layout Verbatim + Ore = 8 \end_layout \begin_layout Verbatim + } \end_layout From 2d77e603f6e2877816992d572ec6fdf837083585 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 8 Oct 2020 14:44:15 +0900 Subject: [PATCH 061/150] Move EditorToolbar into toolbar --- Source/Makefile | 2 +- Source/{GUI => toolbar}/EditorToolbar.cs | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Source/{GUI => toolbar}/EditorToolbar.cs (100%) diff --git a/Source/Makefile b/Source/Makefile index b58b4b0a..558e86b3 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -61,7 +61,6 @@ EL_FILES := \ assembly/Checkers.cs \ assembly/VersionReport.cs \ GUI/CraftBrowser.cs \ - GUI/EditorToolbar.cs \ LaunchClamp/LaunchClamp.cs \ Pad/Launchpad.cs \ Recycler/Recycler.cs \ @@ -103,6 +102,7 @@ EL_FILES := \ lib/KACWrapper.cs \ lib/KerbalStatsWrapper.cs \ lib/Utils.cs \ + toolbar/EditorToolbar.cs \ toolbar/Toolbar.cs \ toolbar/ToolbarWrapper.cs \ AirstreamShield.cs \ diff --git a/Source/GUI/EditorToolbar.cs b/Source/toolbar/EditorToolbar.cs similarity index 100% rename from Source/GUI/EditorToolbar.cs rename to Source/toolbar/EditorToolbar.cs From a86bffb5c524b0a25aa5b01762b499db1da8dcfb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 09:21:13 +0900 Subject: [PATCH 062/150] Create a craft thumbnail component This gets the UI setup and thumbnail loading into one place so I don't have to keep writing it. --- Source/Makefile | 1 + Source/UI/CraftThumb.cs | 99 +++++++++++++++++++++++++++++++++++++++++ Source/UI/CraftView.cs | 53 ++++------------------ Source/lib/Utils.cs | 13 ++++++ 4 files changed, 122 insertions(+), 44 deletions(-) create mode 100644 Source/UI/CraftThumb.cs diff --git a/Source/Makefile b/Source/Makefile index 558e86b3..3953e4f3 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -68,6 +68,7 @@ EL_FILES := \ Target/Target.cs \ UI/BuildView.cs \ UI/BuildManagerView.cs \ + UI/CraftThumb.cs \ UI/CraftView.cs \ UI/IResourceLine.cs \ UI/Localization.cs \ diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs new file mode 100644 index 00000000..471b9030 --- /dev/null +++ b/Source/UI/CraftThumb.cs @@ -0,0 +1,99 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftThumb : UIImage + { + static Texture2D genericCraftThumb; + + public override void CreateUI () + { + if (!genericCraftThumb) { + genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); + } + + base.CreateUI (); + + this.SizeDelta (256, 256) + .MinSize (256, 256) + .PreferredSize (256, 256) + ; + } + + protected override void OnDestroy () + { + Destroy (image.sprite); + base.OnDestroy (); + } + + public static string StockPath (ELCraftType craftType, string craftFile) + { + string type = craftFile.ToString (); + string thumbName = Path.GetFileNameWithoutExtension(craftFile); + return $"Ships/@thumbs/{type}/{thumbName}.png"; + } + + public static string UserPath (ELCraftType craftType, string craftFile) + { + string saveDir = HighLogic.SaveFolder; + string type = craftType.ToString (); + string thumbName = Path.GetFileNameWithoutExtension(craftFile); + return $"thumbs/{saveDir}_{type}_{thumbName}.png"; + } + + public ELCraftThumb Craft (ELCraftType craftType, string craftFile) + { + string saveDir = HighLogic.SaveFolder; + string type = craftType.ToString (); + string thumbName = Path.GetFileNameWithoutExtension(craftFile); + string thumbPath = $"thumbs/{saveDir}_{type}_{thumbName}.png"; + + var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; + if (!EL_Utils.LoadImage (ref thumbTex, thumbPath) + && (craftType == ELCraftType.VAB + || craftType == ELCraftType.SPH)) { + thumbPath = $"Ships/@thumbs/{type}/{thumbName}.png"; + EL_Utils.LoadImage (ref thumbTex, thumbPath); + } + Destroy (image.sprite); + image.sprite = EL_Utils.MakeSprite (thumbTex); + + return this; + } + + public ELCraftThumb Craft (string thumbPath) + { + var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; + bool ok = EL_Utils.LoadImage (ref thumbTex, thumbPath); + Debug.Log ($"[ELCraftThumb] Craft {thumbPath} {ok}"); + Destroy (image.sprite); + image.sprite = EL_Utils.MakeSprite (thumbTex); + + return this; + } + } +} diff --git a/Source/UI/CraftView.cs b/Source/UI/CraftView.cs index c2957ba5..28815dd9 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/CraftView.cs @@ -87,12 +87,11 @@ public RequiredResource (BuildResource build, RMResourceInfo pad) ELResourceDisplay resourceList; UIText craftName; UIText craftBoM; - UIImage craftThumb; + ELCraftThumb craftThumb; ELBuildControl control; FlagBrowser flagBrowser; - ELCraftBrowser craftList; List requiredResources; @@ -218,11 +217,9 @@ public override void CreateUI() .FlexibleLayout (true, false) .SizeDelta (0, 256) .Finish () - .Add (out craftThumb) + .Add (out craftThumb) .Anchor (AnchorPresets.TopLeft) .Pivot (PivotPresets.TopLeft) - .SizeDelta (256, 256) - .MinSize (256, 256) .Finish () .Finish () .Add () @@ -250,10 +247,9 @@ void BuildCraft () } } - void craftSelectComplete (string filename, CBDLoadType lt) + void craftSelectComplete (string filename, ELCraftType craftType) { - control.craftType = craftList.craftType; - craftList = null; + control.craftType = craftType; control.LoadCraft (filename, control.flagname); @@ -267,19 +263,15 @@ void craftSelectComplete (string filename, CBDLoadType lt) void craftSelectCancel () { - craftList = null; selectCraftButton.interactable = true; } void SelectCraft () { - string path = HighLogic.SaveFolder; + string path = ""; - craftList = ELCraftBrowser.Spawn (control.craftType, - path, - craftSelectComplete, - craftSelectCancel, - false); + ELCraftBrowser.OpenDialog (control.craftType, path, + craftSelectComplete, craftSelectCancel); selectCraftButton.interactable = false; } @@ -289,19 +281,6 @@ void OnFlagCancel () selectFlagButton.interactable = true; } - static Sprite MakeSprite (Texture2D tex) - { - var rect = new Rect (0, 0, tex.width, tex.height); - var pivot = new Vector2 (0.5f, 0.5f); - float pixelsPerUnity = 100; - uint extrude = 0; - var type = SpriteMeshType.Tight; - var border = Vector4.zero; - - return UnityEngine.Sprite.Create (tex, rect, pivot, pixelsPerUnity, - extrude, type, border); - } - void OnFlagSelected (FlagBrowser.FlagEntry selected) { Destroy (flagTexture); @@ -345,25 +324,11 @@ void UpdateFlag () control.flagname = control.builder.part.flagURL; } var tex = GameDatabase.Instance.GetTexture (control.flagname, false); - flagTexture = MakeSprite (tex); + flagTexture = EL_Utils.MakeSprite (tex); selectFlagButton.Image (flagTexture); } } - Sprite GetThumbnail() - { - string path = control.filename; - string craftType = control.craftType.ToString(); - string thumbName = Path.GetFileNameWithoutExtension(path); - string thumbPath = $"thumbs/{HighLogic.SaveFolder}_{craftType}_{thumbName}.png"; - var thumbTex = genericCraftThumb; - if (!EL_Utils.LoadImage (ref thumbTex, thumbPath)) { - thumbPath = $"Ships/@thumbs/{craftType}/{thumbName}.png"; - EL_Utils.LoadImage (ref thumbTex, thumbPath); - } - return MakeSprite(genericCraftThumb); - } - void UpdateCraftInfo () { if (control != null) { @@ -377,7 +342,7 @@ void UpdateCraftInfo () if (control.craftBoM != null || control.CreateBoM ()) { craftBoM.Text(String.Join ("\n", control.craftBoM)); } - craftThumb.image.sprite = GetThumbnail(); + craftThumb.Craft (control.craftType, control.filename); } } else { selectedCraft.gameObject.SetActive (false); diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 31b5fe69..7c1e03c3 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -192,5 +192,18 @@ public static bool LoadImage (ref Texture2D tex, string filename) } return ret; } + + public static Sprite MakeSprite (Texture2D tex) + { + var rect = new Rect (0, 0, tex.width, tex.height); + var pivot = new Vector2 (0.5f, 0.5f); + float pixelsPerUnity = 100; + uint extrude = 0; + var type = SpriteMeshType.Tight; + var border = Vector4.zero; + + return Sprite.Create (tex, rect, pivot, pixelsPerUnity, extrude, + type, border); + } } } From e9de1190a8f188aa3aaf1200120d6796c259f546 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 09:22:56 +0900 Subject: [PATCH 063/150] Create a new craft browser It's only the beginning, but the fundamentals are working. --- Source/GUI/CraftBrowser.cs | 230 --------------------------- Source/Makefile | 4 +- Source/UI/CraftBrowser.cs | 309 +++++++++++++++++++++++++++++++++++++ Source/UI/CraftItem.cs | 103 +++++++++++++ Source/UI/CraftItemView.cs | 142 +++++++++++++++++ Source/UI/Localization.cs | 1 + 6 files changed, 558 insertions(+), 231 deletions(-) delete mode 100644 Source/GUI/CraftBrowser.cs create mode 100644 Source/UI/CraftBrowser.cs create mode 100644 Source/UI/CraftItem.cs create mode 100644 Source/UI/CraftItemView.cs diff --git a/Source/GUI/CraftBrowser.cs b/Source/GUI/CraftBrowser.cs deleted file mode 100644 index db69e105..00000000 --- a/Source/GUI/CraftBrowser.cs +++ /dev/null @@ -1,230 +0,0 @@ -/* -This file is part of Extraplanetary Launchpads. - -Extraplanetary Launchpads is free software: you can redistribute it and/or -modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Extraplanetary Launchpads is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Extraplanetary Launchpads. If not, see -. -*/ -using System; -using System.Reflection; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using TMPro; - -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - -using ExtraplanetaryLaunchpads_KACWrapper; - -namespace ExtraplanetaryLaunchpads { - - public enum ELCraftType { VAB, SPH, SubAss }; - - public class ELCraftBrowser : CraftBrowserDialog - { - const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - static GameObject prefab; - static MethodInfo buildCraftList = typeof(CraftBrowserDialog).GetMethod ("BuildCraftList", bindingFlags); - static FieldInfo stoField; - static FieldInfo sltField; - static FieldInfo sfhField; - static FieldInfo svField; - static FieldInfo sdpField; - static FieldInfo onConfigNodeSelected = typeof(CraftBrowserDialog).GetField ("OnConfigNodeSelected", bindingFlags); - - [SerializeField] - private Toggle tabSub; - - private SelectFileCallback onFileSelected; - - static EditorFacility []craftFacility = new EditorFacility[] { - EditorFacility.VAB, - EditorFacility.SPH, - EditorFacility.None, - }; - - static ELCraftType []facilityType = new ELCraftType[] { - ELCraftType.SubAss, - ELCraftType.VAB, - ELCraftType.SPH, - }; - - public ELCraftType craftType - { - get { - return facilityType[(int) facility]; - } - } - - static FieldInfo FindField(int num) - { - var fields = typeof (CraftBrowserDialog).GetFields (BindingFlags.NonPublic | BindingFlags.Instance); - int count = 0; - for (int i = 0, c = fields.Length; i < c; i++) { - if (fields[i].FieldType == typeof(T)) { - count++; - if (count == num) { - return fields[i]; - } - } - } - return null; - } - - // Set the label text for both enabled and disabled versions of the - // subassembly toggle button. - static void SetSubLabels (Transform toggleSub) - { - foreach (Transform xform in toggleSub) { - if (xform.name == "Label") { - var subLabel = xform; - var text = subLabel.GetComponent (); - text.text = "Sub"; - } - } - } - - - static void fallback () - { - Debug.Log ($"[CraftBrowserDialog] how did we get here?"); - } - - static void CreatePrefab () - { - if (stoField == null) { - stoField = FindField (2); - sltField = FindField (3); - sfhField = FindField (2); - svField = FindField (1); - sdpField = FindField (1); - } - var cbdType = typeof (CraftBrowserDialog); - var cbdFields = cbdType.GetFields (bindingFlags); - - var cbdPrefab = AssetBase.GetPrefab ("CraftBrowser"); - prefab = Instantiate (cbdPrefab); - prefab.transform.SetParent (cbdPrefab.transform.parent, false); - prefab.transform.name = "ELCraftBrowser"; - prefab.name = "ELCraftBrowser"; - - var cbd = prefab.GetComponent (); - var ELcb = prefab.AddComponent (); - - foreach (var field in cbdFields) { - field.SetValue(ELcb, field.GetValue(cbd)); - } - - var toggles = prefab.transform.Find("Toggles"); - var toggleMask = toggles.transform.Find ("ToggleMask"); - var toggleSPH = toggleMask.Find ("ToggleSPH"); - var tabSPH = toggleSPH.GetComponent (); - - var toggleSub = Instantiate (toggleSPH.gameObject); - toggleSub.transform.name = "ToggleSub"; - toggleSub.name = "ToggleSub"; - toggleSub.transform.SetParent (toggleMask); - SetSubLabels (toggleSub.transform); - ELcb.tabSub = toggleSub.GetComponent (); - ELcb.tabSub.group = tabSPH.group; - - ELcb.OnBrowseCancelled = fallback; - ELcb.enabled = false; - - Destroy (cbd); - } - - void selCB (ConfigNode n, LoadType t) - { - Debug.Log($"[CraftBrowserDialog] OnConfigNodeSelected - " + selectedEntry.fullFilePath); - onFileSelected(selectedEntry.fullFilePath, t); - } - - public static ELCraftBrowser Spawn (ELCraftType type, string profile, SelectFileCallback onFileSelected, CancelledCallback onCancel, bool showMergeOption) - { - if (prefab == null) { - CreatePrefab (); - } - - var cb = Instantiate (prefab).GetComponent (); - cb.enabled = true; - cb.transform.SetParent (DialogCanvasUtil.DialogCanvasRect, false); - - cb.facility = craftFacility[(int) type]; - cb.showMergeOption = showMergeOption; - cb.OnBrowseCancelled = onCancel; - cb.onFileSelected = onFileSelected; - if (onConfigNodeSelected != null) { - var callback = Delegate.CreateDelegate (onConfigNodeSelected.FieldType, cb, typeof(ELCraftBrowser).GetMethod("selCB", bindingFlags)); - onConfigNodeSelected.SetValue (cb, callback); - } else { - cb.OnFileSelected = onFileSelected; - } - cb.title = "Select a craft to load"; - cb.profile = profile; - - return cb; - } - - public new void Start () - { - if (String.IsNullOrEmpty (profile)) { - // the process of creating the prefab causes Start() to be - // called, which results in a stray Ships directory because - // profile is not yet valid and there is a bug in KSP's - // CraftBrowserDialog. - return; - } - tabSub.isOn = facility == EditorFacility.None; - tabSub.onValueChanged.AddListener (onSubTabToggle); - base.Start (); - if (tabSub.isOn) { - LoadSubassemblies (); - } - } - - void LoadSubassemblies () - { - craftSubfolder = "../Subassemblies"; - var diff = HighLogic.CurrentGame.Parameters.Difficulty; - - bool stock = diff.AllowStockVessels; - diff.AllowStockVessels = false; - - buildCraftList.Invoke (this, null); - - diff.AllowStockVessels = stock; - } - - void onSubTabToggle (bool st) - { - if (st) { - stoField.SetValue (this, false); - (sltField.GetValue (this) as TextMeshProUGUI).gameObject.SetActive (false); - (sfhField.GetValue (this) as GameObject).SetActive (false); - var rXform = svField.GetValue (this) as RectTransform; - var offsetMax = rXform.offsetMax; - rXform.offsetMax = new Vector2 (offsetMax.x, -56f); - if (SteamManager.Initialized) { - (sdpField.GetValue (this) as UIPanelTransition).Transition (0); - } - - facility = EditorFacility.None; - LoadSubassemblies (); - } - } - } -} diff --git a/Source/Makefile b/Source/Makefile index 3953e4f3..ac499c44 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -60,7 +60,6 @@ EL_FILES := \ assembly/AssemblyInfo.cs \ assembly/Checkers.cs \ assembly/VersionReport.cs \ - GUI/CraftBrowser.cs \ LaunchClamp/LaunchClamp.cs \ Pad/Launchpad.cs \ Recycler/Recycler.cs \ @@ -68,7 +67,10 @@ EL_FILES := \ Target/Target.cs \ UI/BuildView.cs \ UI/BuildManagerView.cs \ + UI/CraftBrowser.cs \ UI/CraftThumb.cs \ + UI/CraftItem.cs \ + UI/CraftItemView.cs \ UI/CraftView.cs \ UI/IResourceLine.cs \ UI/Localization.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs new file mode 100644 index 00000000..f8017689 --- /dev/null +++ b/Source/UI/CraftBrowser.cs @@ -0,0 +1,309 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + public enum ELCraftType { VAB, SPH, SubAss }; + + public class ELCraftBrowser : Window + { + public delegate void SelectFileCallback(string fullPath, + ELCraftType craftType); + public SelectFileCallback OnFileSelected; + + public delegate void CancelledCallback(); + public CancelledCallback OnBrowseCancelled; + + static EditorFacility []craftFacility = new EditorFacility[] { + EditorFacility.VAB, + EditorFacility.SPH, + EditorFacility.None, + }; + + static ELCraftType []facilityType = new ELCraftType[] { + ELCraftType.SubAss, + ELCraftType.VAB, + ELCraftType.SPH, + }; + + public ELCraftType craftType { get; private set; } + + ScrollView craftList; + ELCraftThumb craftThumb; + ScrollView craftInfo; + UIText craftDescription; + UIButton loadButton; + + ELCraftItem.List craftItems; + ToggleGroup craftGroup; + ELCraftItem _selectedCraft; + ELCraftItem selectedCraft + { + get { return _selectedCraft; } + set { + _selectedCraft = value; + UpdateCraftInfo (); + } + } +/* + public ELCraftType craftType + { + get { + return facilityType[(int) facility]; + } + }*/ + + public override void CreateUI () + { + base.CreateUI (); + + UIScrollbar list_scrollbar; + UIScrollbar info_scrollbar; + + this.Title (ELLocalization.SelectCraft) + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .PreferredSizeFitter (true, true) + .Anchor (AnchorPresets.MiddleCenter) + .Pivot (PivotPresets.MiddleCenter) + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + + .Add (out craftList) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .PreferredSize (321, -1) + .Add (out list_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Add () + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add (out craftThumb) + .Finish () + .Add (out craftInfo) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout (true, false) + .PreferredSize (-1, 256) + .Add (out info_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () + .Finish () + .Add () + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add () + .Text (ELLocalization.Cancel) + .OnClick (Cancel) + .Finish () + .Add (out loadButton) + .Text (ELLocalization.Load) + .OnClick (LoadCraft) + .Finish () + .Finish () + .Add () + .Text (ELVersionReport.GetVersion ()) + .Alignment (TextAlignmentOptions.Center) + .Size (12) + .FlexibleLayout (true, false) + .Finish () + .Finish (); + + craftList.VerticalScrollbar = list_scrollbar; + craftList.Viewport.FlexibleLayout (true, true); + craftList.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .ToggleGroup (out craftGroup) + .Finish (); + + craftInfo.VerticalScrollbar = info_scrollbar; + craftInfo.Viewport.FlexibleLayout (true, true); + craftInfo.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .Add (out craftDescription) + .Alignment (TextAlignmentOptions.TopLeft) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () + .Finish (); + + + relativePath = ""; + craftThumb.Craft (ELCraftType.SubAss, ""); + + craftItems = new ELCraftItem.List (craftGroup); + craftItems.Content = craftList.Content; + craftItems.onSelected = OnSelected; + } + + void Cancel () + { + OnBrowseCancelled (); + SetActive (false); + } + + void pipelineSucceed (ConfigNode node, ELCraftItem craft) + { + if (node != craft.node) { + craft.node.Save (craft.fullPath + ".original"); + node.Save (craft.fullPath); + } + OnFileSelected (selectedCraft.fullPath, selectedCraft.type); + } + + void pipelineFail (KSPUpgradePipeline.UpgradeFailOption opt, ConfigNode node, ELCraftItem craft) + { + if (opt == KSPUpgradePipeline.UpgradeFailOption.Cancel) { + OnBrowseCancelled (); + } else if (opt == KSPUpgradePipeline.UpgradeFailOption.LoadAnyway) { + pipelineSucceed (node, craft); + } + } + + void LoadCraft () + { + SetActive (false); + KSPUpgradePipeline.Process (selectedCraft.node, selectedCraft.name, + SaveUpgradePipeline.LoadContext.Craft, + node => { pipelineSucceed (node, selectedCraft); }, + (opt, node) => { pipelineFail (opt, node, selectedCraft); }); + } + + string relativePath; + + void OnSelected (ELCraftItem craft) + { + if (selectedCraft == craft && Mouse.Left.GetDoubleClick (true)) { + Debug.Log ($" double click!!"); + LoadCraft (); + } else { + selectedCraft = craft; + } + } + + void UpdateCraftInfo () + { + if (selectedCraft != null) { + craftThumb.Craft (selectedCraft.thumbPath); + craftDescription.Text (selectedCraft.description); + loadButton.interactable = true; + } else { + craftDescription.Text (""); + craftThumb.Craft (""); + loadButton.interactable = false; + } + } + + void SetRelativePath (ELCraftType craftType, string path) + { + SetActive (true); + this.craftType = craftType; + relativePath = path; + ScanDirectory (craftType, path); + } + + bool ScanDirectory (ELCraftType type, string path) + { + string profile = HighLogic.SaveFolder; + string savePath = $"{KSPUtil.ApplicationRootPath}saves/{profile}/"; + + craftItems.Clear (); + selectedCraft = null; + + switch (type) { + case ELCraftType.VAB: + case ELCraftType.SPH: + path = $"{savePath}Ships/{type.ToString ()}/{path}"; + break; + case ELCraftType.SubAss: + path = $"{savePath}Subassemblies/{path}"; + break; + } + + var directory = new DirectoryInfo (path); + var files = directory.GetFiles ("*.craft"); + + for (int i = 0; i < files.Length; i++) { + var fi = files[i]; + string fp = fi.FullName; + string mp = fi.FullName.Replace (fi.Extension, ".loadmeta"); + string tp = ELCraftThumb.UserPath (type, fp); + craftItems.Add (new ELCraftItem (fp, mp, tp, type)); + } + + UIKit.UpdateListContent (craftItems); + return true; + } + + static ELCraftBrowser craftBrowser; + + public static void OpenDialog (ELCraftType craftType, string path, + SelectFileCallback onFileSelected, + CancelledCallback onCancel) + { + if (!craftBrowser) { + craftBrowser = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELCraftBrowser"); + } + craftBrowser.OnFileSelected = onFileSelected; + craftBrowser.OnBrowseCancelled = onCancel; + craftBrowser.SetRelativePath (craftType, path); + } + } +} diff --git a/Source/UI/CraftItem.cs b/Source/UI/CraftItem.cs new file mode 100644 index 00000000..1163ea95 --- /dev/null +++ b/Source/UI/CraftItem.cs @@ -0,0 +1,103 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System.IO; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using KSP.UI.Screens; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftItem + { + CraftProfileInfo info; + public string fullPath { get; private set; } + public string name { get { return info.shipName; } } + public string description { get { return info.description; } } + public float cost { get { return info.totalCost; } } + public int partCount { get { return info.partCount; } } + public int stageCount { get { return info.stageCount; } } + public string message { get; private set; } + public string thumbPath { get; private set; } + public ELCraftType type { get; private set; } + ConfigNode _node; + public ConfigNode node + { + get { + if (_node == null) { + _node = ConfigNode.Load (fullPath); + } + return _node; + } + set { _node = value; } + } + + public ELCraftItem (string craftPath, string metaPath, string thumbPath, ELCraftType craftType) + { + fullPath = craftPath; + info = new CraftProfileInfo (); + if (File.Exists (metaPath)) { + var node = ConfigNode.Load (metaPath); + info.Load (node); + } else { + var node = ConfigNode.Load (craftPath); + info.LoadDetailsFromCraftFile (node, craftPath); + this.node = node; + } + this.thumbPath = thumbPath; + type = craftType; + } + + public class Dict : Dictionary { } + public class List : List, UIKit.IListObject + { + ToggleGroup group; + public UnityAction onSelected { get; set; } + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Group (group) + .OnSelected (onSelected) + .Craft (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var view = obj.GetComponent (); + view.Craft (this[index]); + } + + public List (ToggleGroup group) + { + this.group = group; + } + } + } +} diff --git a/Source/UI/CraftItemView.cs b/Source/UI/CraftItemView.cs new file mode 100644 index 00000000..6194f1f8 --- /dev/null +++ b/Source/UI/CraftItemView.cs @@ -0,0 +1,142 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using KSP.Localization; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftItemView : LayoutPanel, IPointerEnterHandler, IPointerExitHandler + { + ELCraftItem craft; + new UIText name; + UIText stats; + UIText cost; + UIText message; + ELCraftThumb thumb; + + public class ELCraftItemViewEvent : UnityEvent { } + ELCraftItemViewEvent onSelected; + + Toggle toggle; + + public override void CreateUI() + { + base.CreateUI (); + + onSelected = new ELCraftItemViewEvent (); + + toggle = gameObject.AddComponent (); + toggle.targetGraphic = BackGround; + toggle.onValueChanged.AddListener (onValueChanged); + + var statsMin = new Vector2 (0, 0); + var statsMax = new Vector2 (124f/234f, 1); + var costMin = new Vector2 (124f/234f, 0); + var costMax = new Vector2 (1, 1); + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Padding (3) + .Add () + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Add (out name) + .Alignment (TextAlignmentOptions.Left) + .Size (18) + .PreferredSize (234, -1) + .Finish () + .Add () + .DoPreferredHeight (true) + .FlexibleLayout (true, true) + .Add (out stats) + .Alignment (TextAlignmentOptions.Left) + .Size (15) + .Anchor (statsMin, statsMax) + .SizeDelta (0, 0) + .Finish () + .Add (out cost) + .Alignment (TextAlignmentOptions.Left) + .Size (15) + .Anchor (costMin, costMax) + .SizeDelta (0, 0) + .Finish () + .Finish () + .Add (out message) + .Alignment (TextAlignmentOptions.Left) + .Size (15) + .FlexibleLayout (true, false) + .Finish () + .Finish () + .Add () + .PreferredSize (64, 64) + .Add (out thumb) + .AspectRatioSizeFitter (AspectRatioFitter.AspectMode.FitInParent, 1) + .Finish () + ; + // + } + + void onValueChanged (bool on) + { + if (on) { + onSelected.Invoke (craft); + } + } + + public ELCraftItemView Group (ToggleGroup group) + { + toggle.group = group; + return this; + } + + public ELCraftItemView OnSelected (UnityAction action) + { + onSelected.AddListener (action); + return this; + } + + public ELCraftItemView Craft (ELCraftItem craft) + { + this.craft = craft; + name.Text (craft.name); + stats.Text (Localizer.Format("#autoLOC_452442", craft.partCount, + craft.stageCount)); + cost.Text (Localizer.Format("#autoLOC_6003099", craft.cost)); + message.Text (craft.message); + thumb.Craft (craft.thumbPath); + return this; + } +#region OnPointerEnter/Exit + public void OnPointerEnter (PointerEventData eventData) + { + } + + public void OnPointerExit (PointerEventData eventData) + { + } +#endregion + } +} diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index c87ea281..7d4fdc8f 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -49,6 +49,7 @@ public static class ELLocalization public static string RenameSurveyStation { get; } = "Rename Survey Station"; public static string Name { get; } = "Name"; public static string OK { get; } = "OK"; + public static string Load { get; } = "Load"; public static string Cancel { get; } = "Cancel"; public static string StartTransfer { get; } = "Start Transfer"; public static string StopTransfer { get; } = "Stop Transfer"; From 506947a53dbfe21860a9180689477ef5fc1fe3fe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 09:24:34 +0900 Subject: [PATCH 064/150] Fix a lapse in fluency --- Source/UI/RenameDialog.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UI/RenameDialog.cs b/Source/UI/RenameDialog.cs index c58f3268..b33a6144 100644 --- a/Source/UI/RenameDialog.cs +++ b/Source/UI/RenameDialog.cs @@ -99,8 +99,8 @@ public override void CreateUI() .Alignment (TextAlignmentOptions.Center) .Size (12) .FlexibleLayout (true, false) - .Finish (); - Finish (); + .Finish () + .Finish (); } void onSubmit (string str) From f6b2b68f809b884c472dbf6a829745f1670529ed Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 13:00:01 +0900 Subject: [PATCH 065/150] Fix stock craft thumb path vim completion fail :P --- Source/UI/CraftThumb.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index 471b9030..a1d24d3f 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -52,7 +52,7 @@ protected override void OnDestroy () public static string StockPath (ELCraftType craftType, string craftFile) { - string type = craftFile.ToString (); + string type = craftType.ToString (); string thumbName = Path.GetFileNameWithoutExtension(craftFile); return $"Ships/@thumbs/{type}/{thumbName}.png"; } From 665d0342e5e743628cf8f794daa4f7f5bcf75f00 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 13:10:09 +0900 Subject: [PATCH 066/150] Implement craft type selection --- KodeUI | 2 +- Source/Makefile | 3 +- Source/UI/CraftBrowser.cs | 42 ++++++-- Source/UI/CraftItem.cs | 9 ++ Source/UI/CraftItemView.cs | 6 ++ Source/UI/CraftTypeSelector.cs | 184 +++++++++++++++++++++++++++++++++ Source/UI/Localization.cs | 5 + Source/UI/MiniToggle.cs | 6 ++ Source/UI/ToggleText.cs | 6 ++ 9 files changed, 252 insertions(+), 11 deletions(-) create mode 100644 Source/UI/CraftTypeSelector.cs diff --git a/KodeUI b/KodeUI index 6a37f966..3d12d867 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 6a37f966838dca31b4c38064e5482a0e724ec81c +Subproject commit 3d12d867cd88894d6d7db79d6cf3a9bf2863f031 diff --git a/Source/Makefile b/Source/Makefile index ac499c44..eb3f7a16 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -68,9 +68,10 @@ EL_FILES := \ UI/BuildView.cs \ UI/BuildManagerView.cs \ UI/CraftBrowser.cs \ - UI/CraftThumb.cs \ UI/CraftItem.cs \ UI/CraftItemView.cs \ + UI/CraftThumb.cs \ + UI/CraftTypeSelector.cs \ UI/CraftView.cs \ UI/IResourceLine.cs \ UI/Localization.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index f8017689..66fa65ea 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -33,7 +33,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public enum ELCraftType { VAB, SPH, SubAss }; + public enum ELCraftType { VAB, SPH, SubAss, Part }; public class ELCraftBrowser : Window { @@ -58,6 +58,7 @@ public delegate void SelectFileCallback(string fullPath, public ELCraftType craftType { get; private set; } + ELCraftTypeSelector typeSelector; ScrollView craftList; ELCraftThumb craftThumb; ScrollView craftInfo; @@ -97,6 +98,10 @@ public override void CreateUI () .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) .Pivot (PivotPresets.MiddleCenter) + .Add (out typeSelector) + .OnSelectionChanged (CraftTypeSelected) + .FlexibleLayout (true, true) + .Finish () .Add () .Horizontal () .ControlChildSize (true, true) @@ -251,29 +256,42 @@ void UpdateCraftInfo () } } - void SetRelativePath (ELCraftType craftType, string path) + void CraftTypeSelected () + { + SetRelativePath (typeSelector.craftType, typeSelector.stockCraft, ""); + } + + void SetRelativePath (ELCraftType craftType, bool stock, string path) { SetActive (true); this.craftType = craftType; relativePath = path; - ScanDirectory (craftType, path); + ScanDirectory (craftType, stock, path); } - bool ScanDirectory (ELCraftType type, string path) + bool ScanDirectory (ELCraftType type, bool stock, string path) { string profile = HighLogic.SaveFolder; - string savePath = $"{KSPUtil.ApplicationRootPath}saves/{profile}/"; + string basePath = KSPUtil.ApplicationRootPath; craftItems.Clear (); selectedCraft = null; + if (!stock) { + basePath = basePath + $"saves/{profile}/"; + } + switch (type) { case ELCraftType.VAB: case ELCraftType.SPH: - path = $"{savePath}Ships/{type.ToString ()}/{path}"; + path = $"{basePath}Ships/{type.ToString ()}/{path}"; break; case ELCraftType.SubAss: - path = $"{savePath}Subassemblies/{path}"; + var subassPath = $"{basePath}Subassemblies/"; + if (!Directory.Exists (subassPath)) { + Directory.CreateDirectory (subassPath); + } + path = $"{subassPath}{path}"; break; } @@ -284,11 +302,17 @@ bool ScanDirectory (ELCraftType type, string path) var fi = files[i]; string fp = fi.FullName; string mp = fi.FullName.Replace (fi.Extension, ".loadmeta"); - string tp = ELCraftThumb.UserPath (type, fp); + string tp; + if (stock) { + tp = ELCraftThumb.StockPath (type, fp); + } else { + tp = ELCraftThumb.UserPath (type, fp); + } craftItems.Add (new ELCraftItem (fp, mp, tp, type)); } UIKit.UpdateListContent (craftItems); + craftItems.Select (0); return true; } @@ -303,7 +327,7 @@ public static void OpenDialog (ELCraftType craftType, string path, } craftBrowser.OnFileSelected = onFileSelected; craftBrowser.OnBrowseCancelled = onCancel; - craftBrowser.SetRelativePath (craftType, path); + craftBrowser.SetRelativePath (craftType, false, path); } } } diff --git a/Source/UI/CraftItem.cs b/Source/UI/CraftItem.cs index 1163ea95..52b75f6d 100644 --- a/Source/UI/CraftItem.cs +++ b/Source/UI/CraftItem.cs @@ -98,6 +98,15 @@ public List (ToggleGroup group) { this.group = group; } + + public void Select (int index) + { + if (index >= 0 && index < Count) { + var child = Content.rectTransform.GetChild (index); + var view = child.GetComponent (); + view.Select (); + } + } } } } diff --git a/Source/UI/CraftItemView.cs b/Source/UI/CraftItemView.cs index 6194f1f8..d1af4544 100644 --- a/Source/UI/CraftItemView.cs +++ b/Source/UI/CraftItemView.cs @@ -118,6 +118,12 @@ public ELCraftItemView OnSelected (UnityAction action) return this; } + public ELCraftItemView Select () + { + toggle.isOn = true; + return this; + } + public ELCraftItemView Craft (ELCraftItem craft) { this.craft = craft; diff --git a/Source/UI/CraftTypeSelector.cs b/Source/UI/CraftTypeSelector.cs new file mode 100644 index 00000000..686ba822 --- /dev/null +++ b/Source/UI/CraftTypeSelector.cs @@ -0,0 +1,184 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using UnityEngine; +using UnityEngine.UI; +using UnityEngine.Events; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftTypeSelector : UIObject, ILayoutElement + { + ToggleText vabToggle; + ToggleText sphToggle; + ToggleText subToggle; + ToggleText partToggle; + ToggleText stockToggle; + + public class ELCraftTypeSelectorEvent : UnityEvent { } + ELCraftTypeSelectorEvent onSelectionChanged; + + public ELCraftType craftType { get; private set; } + public bool stockCraft { get; private set; } + + protected override string GetStylePath(bool isParent=false) + { + if (isParent) { + return GetParentStylePath (); + } else { + return base.GetStylePath(isParent); + } + } + + public override void CreateUI () + { + onSelectionChanged = new ELCraftTypeSelectorEvent (); + + var vabMin = new Vector2 (0.00f, 0.5f); + var vabMax = new Vector2 (0.25f, 1.0f); + var sphMin = new Vector2 (0.25f, 0.5f); + var sphMax = new Vector2 (0.50f, 1.0f); + var subMin = new Vector2 (0.50f, 0.5f); + var subMax = new Vector2 (0.75f, 1.0f); + var partMin = new Vector2 (0.75f, 0.5f); + var partMax = new Vector2 (1.00f, 1.0f); + var stockMin= new Vector2 (0.00f, 0.0f); + var stockMax= new Vector2 (1.00f, 0.5f); + + ToggleGroup group; + + this.ToggleGroup (out group) + .Add (out vabToggle) + .Text (ELLocalization.VAB) + .Group (group) + .OnValueChanged (on => { if (on) { SetType (ELCraftType.VAB); } }) + .Anchor (vabMin, vabMax) + .SizeDelta (0, 0) + .Finish () + .Add (out sphToggle) + .Text (ELLocalization.SPH) + .Group (group) + .OnValueChanged (on => { if (on) { SetType (ELCraftType.SPH); } }) + .Anchor (sphMin, sphMax) + .SizeDelta (0, 0) + .Finish () + .Add (out subToggle) + .Text (ELLocalization.SubAss) + .Group (group) + .OnValueChanged (on => { if (on) { SetType (ELCraftType.SubAss); } }) + .Anchor (subMin, subMax) + .SizeDelta (0, 0) + .Finish () + .Add (out partToggle) + .Text (ELLocalization.Part) + .Group (group) + .OnValueChanged (on => { if (on) { SetType (ELCraftType.Part); } }) + .Anchor (partMin, partMax) + .SizeDelta (0, 0) + .Finish () + .Add (out stockToggle) + .Text (ELLocalization.StockVessels) + .OnValueChanged (SetStockCraft) + .Anchor (stockMin, stockMax) + .SizeDelta (0, 0) + .Finish () + ; + } + + public override void Style () + { + } + + void SetType (ELCraftType type) + { + if (type == ELCraftType.VAB || type == ELCraftType.SPH) { + stockToggle.interactable = true; + stockToggle.SetIsOnWithoutNotify (stockCraft); + } else { + stockToggle.interactable = false; + stockToggle.SetIsOnWithoutNotify (false); + } + craftType = type; + onSelectionChanged.Invoke (); + } + + void SetStockCraft (bool on) + { + stockCraft = on; + onSelectionChanged.Invoke (); + } + + public ELCraftTypeSelector OnSelectionChanged (UnityAction action) + { + onSelectionChanged.AddListener (action); + return this; + } +#region ILayoutElement + Vector2 minSize; + Vector2 preferredSize; + + public void CalculateLayoutInputHorizontal() + { + float a, b, c, d, e; + + a = LayoutUtility.GetMinSize (vabToggle.rectTransform, 0); + b = LayoutUtility.GetMinSize (sphToggle.rectTransform, 0); + c = LayoutUtility.GetMinSize (subToggle.rectTransform, 0); + d = LayoutUtility.GetMinSize (partToggle.rectTransform, 0); + e = LayoutUtility.GetMinSize (stockToggle.rectTransform, 0); + minSize.x = Mathf.Max (a + b + c + d, e); + + a = LayoutUtility.GetPreferredSize (vabToggle.rectTransform, 0); + b = LayoutUtility.GetPreferredSize (sphToggle.rectTransform, 0); + c = LayoutUtility.GetPreferredSize (subToggle.rectTransform, 0); + d = LayoutUtility.GetPreferredSize (partToggle.rectTransform, 0); + e = LayoutUtility.GetPreferredSize (stockToggle.rectTransform, 0); + preferredSize.x = Mathf.Max (a + b + c + d, e); + } + + public void CalculateLayoutInputVertical() + { + float a, b, c, d, e; + + a = LayoutUtility.GetMinSize (vabToggle.rectTransform, 1); + b = LayoutUtility.GetMinSize (sphToggle.rectTransform, 1); + c = LayoutUtility.GetMinSize (subToggle.rectTransform, 1); + d = LayoutUtility.GetMinSize (partToggle.rectTransform, 1); + e = LayoutUtility.GetMinSize (stockToggle.rectTransform, 1); + minSize.y = Mathf.Max (a, Mathf.Max (b, Mathf.Max (c, d))) + e; + + a = LayoutUtility.GetPreferredSize (vabToggle.rectTransform, 1); + b = LayoutUtility.GetPreferredSize (sphToggle.rectTransform, 1); + c = LayoutUtility.GetPreferredSize (subToggle.rectTransform, 1); + d = LayoutUtility.GetPreferredSize (partToggle.rectTransform, 1); + e = LayoutUtility.GetPreferredSize (stockToggle.rectTransform, 1); + preferredSize.y = Mathf.Max (a, Mathf.Max (b, Mathf.Max (c, d))) + e; + } + + public int layoutPriority { get { return 0; } } + public float minWidth { get { return minSize.x; } } + public float preferredWidth { get { return preferredSize.x; } } + public float flexibleWidth { get { return -1; } } + public float minHeight { get { return minSize.y; } } + public float preferredHeight { get { return preferredSize.y; } } + public float flexibleHeight { get { return -1; } } +#endregion + } +} diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 7d4fdc8f..49718ae0 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -58,5 +58,10 @@ public static class ELLocalization public static string Out { get; } = "Out"; public static string WarningNoSite { get; } = "No sites found."; public static string WarningNoSite2 { get; } = "No sites found. Explosions likely."; + public static string VAB { get; } = "VAB"; // #autoLOC_6002108 + public static string SPH { get; } = "SPH"; // #autoLOC_6002119 + public static string SubAss { get; } = "Sub"; + public static string Part { get; } = "Part"; // #autoLOC_6100048 + public static string StockVessels { get; } = "Stock Vessels"; } } diff --git a/Source/UI/MiniToggle.cs b/Source/UI/MiniToggle.cs index 3502b18b..485c2d9c 100644 --- a/Source/UI/MiniToggle.cs +++ b/Source/UI/MiniToggle.cs @@ -27,6 +27,12 @@ public class MiniToggle : Layout { UIToggle toggle; + public bool interactable + { + get { return toggle.interactable; } + set { toggle.interactable = value; } + } + public override void CreateUI() { var toggleMin = new Vector2 (0, 0.25f); diff --git a/Source/UI/ToggleText.cs b/Source/UI/ToggleText.cs index 0cd5eda0..5ca4c019 100644 --- a/Source/UI/ToggleText.cs +++ b/Source/UI/ToggleText.cs @@ -29,6 +29,12 @@ public class ToggleText : Layout MiniToggle toggle; UIText label; + public bool interactable + { + get { return toggle.interactable; } + set { toggle.interactable = value; } + } + public override void CreateUI() { var toggleMin = new Vector2 (0, 0.25f); From 47104e52efd8136cfcc1347143d8a205f1e807ed Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 13:52:51 +0900 Subject: [PATCH 067/150] Get forced craft selection working --- Source/UI/CraftBrowser.cs | 1 - Source/UI/CraftItem.cs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index 66fa65ea..c810178f 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -236,7 +236,6 @@ void LoadCraft () void OnSelected (ELCraftItem craft) { if (selectedCraft == craft && Mouse.Left.GetDoubleClick (true)) { - Debug.Log ($" double click!!"); LoadCraft (); } else { selectedCraft = craft; diff --git a/Source/UI/CraftItem.cs b/Source/UI/CraftItem.cs index 52b75f6d..9492aafc 100644 --- a/Source/UI/CraftItem.cs +++ b/Source/UI/CraftItem.cs @@ -102,6 +102,7 @@ public List (ToggleGroup group) public void Select (int index) { if (index >= 0 && index < Count) { + group.SetAllTogglesOff (false); var child = Content.rectTransform.GetChild (index); var view = child.GetComponent (); view.Select (); From 091d04371e66e9ea173357d18e056b163fb4ad32 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 9 Oct 2020 22:11:57 +0900 Subject: [PATCH 068/150] Start work on on-demand thumbnail generation It sort of works, but with a few problems. The main one is the displayed thumbnails don't update automatically, but it turns out the textures are not being handled properly so I left that for now as sorting out the texture handling should sort out the thumbnails too. The other problem is that because everything is in the current scene, the current lighting affects the thumbnails. --- KodeUI | 2 +- Source/UI/CraftBrowser.cs | 14 +++++++++ Source/UI/CraftThumb.cs | 64 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 5 deletions(-) diff --git a/KodeUI b/KodeUI index 3d12d867..e4ac322e 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 3d12d867cd88894d6d7db79d6cf3a9bf2863f031 +Subproject commit e4ac322e5fd09675e31241bd278e5f87158389be diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index c810178f..0686a373 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -64,6 +64,7 @@ public delegate void SelectFileCallback(string fullPath, ScrollView craftInfo; UIText craftDescription; UIButton loadButton; + UIButton generateThumb; ELCraftItem.List craftItems; ToggleGroup craftGroup; @@ -124,6 +125,13 @@ public override void CreateUI () .ControlChildSize (true, true) .ChildForceExpand (false,false) .Add (out craftThumb) + .Add (out generateThumb) + .Text ("Generate") + .OnClick (GenerateThumb) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Color (new UnityEngine.Color (0,0,0,0)) + .Finish () .Finish () .Add (out craftInfo) .Horizontal (false) @@ -198,6 +206,12 @@ public override void CreateUI () craftItems.onSelected = OnSelected; } + void GenerateThumb () + { + ELCraftThumb.Capture (selectedCraft.node, selectedCraft.type, + selectedCraft.fullPath); + } + void Cancel () { OnBrowseCancelled (); diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index a1d24d3f..8ee27879 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -17,8 +17,10 @@ You should have received a copy of the GNU General Public License */ using System; using System.IO; +using System.Collections; using System.Collections.Generic; using UnityEngine; +using UnityEngine.SceneManagement; using UnityEngine.Events; using TMPro; @@ -50,6 +52,63 @@ protected override void OnDestroy () base.OnDestroy (); } + static Vector4 angles; + static float fovFactor = 0.9f; + + static IEnumerator capture (ShipConstruct ship, string thumbName) + { + yield return null; + + var savedScene = SceneManager.GetActiveScene (); + CraftThumbnail.TakeSnaphot (ship, 256, "thumbs", thumbName, + angles.x, angles.y, angles.z, angles.w, + fovFactor); + for (int i = ship.parts.Count; i-- > 0; ) { + UnityEngine.Object.Destroy (ship.parts[i].gameObject); + } + } + + public static void Capture (ConfigNode craft, ELCraftType craftType, string craftFile) + { + var ship = new ShipConstruct (); + ship.LoadShip (craft); + + if (ship.vesselDeltaV != null) { + // The delta-v module is not needed. It has its own gameObject + // for ShipConstruct. + UnityEngine.Object.Destroy (ship.vesselDeltaV.gameObject); + ship.vesselDeltaV = null; + } + // Need to keep the parts around for a few frames, but + // Part.FixedUpdate throws if things are not set up properly + // (which they won't be), but setting the state to PLACEMENT gets + // around this by tricking the part into thinking its being placed + // in the editor + for (int i = ship.parts.Count; i-- > 0; ) { + ship.parts[i].State = PartStates.PLACEMENT; + } + + if (craftType == ELCraftType.SPH) { + angles = new Vector4 (35, 135, 35, 135); + } else { + angles = new Vector4 (45, 45, 45, 45); + } + + string thumbName = UserThumbName (craftType, craftFile); + // Need to wait a frame for the parts to be renderable + // (don't know why, but my guess is to give the various renderers + // a chance to set themselves up) + HighLogic.fetch.StartCoroutine (capture (ship, thumbName)); + } + + public static string UserThumbName (ELCraftType craftType, string craftFile) + { + string saveDir = HighLogic.SaveFolder; + string type = craftType.ToString (); + string thumbName = Path.GetFileNameWithoutExtension(craftFile); + return $"{saveDir}_{type}_{thumbName}"; + } + public static string StockPath (ELCraftType craftType, string craftFile) { string type = craftType.ToString (); @@ -59,10 +118,7 @@ public static string StockPath (ELCraftType craftType, string craftFile) public static string UserPath (ELCraftType craftType, string craftFile) { - string saveDir = HighLogic.SaveFolder; - string type = craftType.ToString (); - string thumbName = Path.GetFileNameWithoutExtension(craftFile); - return $"thumbs/{saveDir}_{type}_{thumbName}.png"; + return $"thumbs/{UserThumbName (craftType, craftFile)}.png"; } public ELCraftThumb Craft (ELCraftType craftType, string craftFile) From 6321454347bff35dcb43940c48c8337de4d89278 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 12:05:11 +0900 Subject: [PATCH 069/150] Add new ship icon from JadeOfMaar Thank you :) --- Assets/EL_UntitledSpacecraft.svg | 305 +++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 Assets/EL_UntitledSpacecraft.svg diff --git a/Assets/EL_UntitledSpacecraft.svg b/Assets/EL_UntitledSpacecraft.svg new file mode 100644 index 00000000..3214c22f --- /dev/null +++ b/Assets/EL_UntitledSpacecraft.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From baf2d8927a61ee019f88515fb2c972c25e267a05 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 14:35:26 +0900 Subject: [PATCH 070/150] Use a custom camera and lighting right for thumbs This makes the lighting of the thumbnail independent of the local scene lighting, though it's not quite right (but that's just more tweaking). --- Source/UI/CraftThumb.cs | 137 +++++++++++++++++++++++++++++++++++----- Source/lib/Utils.cs | 27 ++++++++ 2 files changed, 149 insertions(+), 15 deletions(-) diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index 8ee27879..1d26928c 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -20,7 +20,6 @@ You should have received a copy of the GNU General Public License using System.Collections; using System.Collections.Generic; using UnityEngine; -using UnityEngine.SceneManagement; using UnityEngine.Events; using TMPro; @@ -52,20 +51,116 @@ protected override void OnDestroy () base.OnDestroy (); } - static Vector4 angles; + const int thumbLayer = 8; + const int thumbMask = 1 << thumbLayer; + const float thumbLightDist = 40; + const float thumbFov = 30; + const int thumbResolution = 256; + const int thumbBits = 24; + + static Vector2 angles; static float fovFactor = 0.9f; + static GameObject thumbRig; + static GameObject thumbPivot; + static Camera thumbCamera; + + static Vector3 []tetraHedron = { + new Vector3 ( 1, 1, 1), + new Vector3 (-1, 1,-1), + new Vector3 (-1,-1, 1), + new Vector3 ( 1,-1,-1), + }; + + static void CreateRig () + { + thumbRig = new GameObject ("Thumb Rig"); + + thumbPivot = new GameObject ("Thumb Pivot"); + thumbPivot.transform.SetParent (thumbRig.transform, false); + + var camObj = new GameObject ("Thumb Camera"); + camObj.transform.SetParent (thumbPivot.transform, false); + + thumbCamera = camObj.AddComponent (); + thumbCamera.enabled = false; // disable automatic rendering + thumbCamera.cullingMask = thumbMask; + thumbCamera.clearFlags = CameraClearFlags.SolidColor; + thumbCamera.backgroundColor = UnityEngine.Color.clear; + thumbCamera.fieldOfView = thumbFov; + + for (int i = 0; i < tetraHedron.Length; i++) { + var lightObj = new GameObject ("Thumb Light"); + lightObj.transform.SetParent (thumbRig.transform, false); + lightObj.transform.localPosition = tetraHedron[i] * thumbLightDist; + lightObj.transform.localRotation = Quaternion.LookRotation (-tetraHedron[i], Vector3.up); + Debug.Log ($"[ELCraftThumb] CreateRig light {i} {lightObj.transform.localPosition} {lightObj.transform.forward}"); + + var light = lightObj.AddComponent (); + light.cullingMask = thumbMask; + light.colorTemperature = 6570; + light.type = LightType.Spot; + light.spotAngle = 55; + light.range = thumbLightDist * 10; + light.intensity = 1; + } + + EL_Utils.SetLayer (thumbRig, thumbLayer, true); + } + + static Texture2D takeSnapshot (ShipConstruct ship) + { + Vector3 size = ShipConstruction.CalculateCraftSize (ship); + float dist = KSPCameraUtil.GetDistanceToFit (size, thumbFov * fovFactor); + thumbRig.transform.position = ShipConstruction.FindCraftCenter (ship, true); + thumbCamera.transform.localPosition = new Vector3 (0, 0, -dist); + thumbPivot.transform.localRotation = Quaternion.AngleAxis (angles.y, Vector3.up) * Quaternion.AngleAxis (angles.x, Vector3.right); + + var rect = new Rect (0, 0, thumbResolution, thumbResolution); + var buffer = new RenderTexture ((int) rect.width, (int) rect.height, thumbBits, RenderTextureFormat.Default); + thumbCamera.targetTexture = buffer; + thumbCamera.Render (); + + var saveActive = RenderTexture.active; + RenderTexture.active = buffer; + var tex = new Texture2D ((int) rect.width, (int) rect.height, TextureFormat.ARGB32, false); + tex.ReadPixels (rect, 0, 0); + + RenderTexture.active = saveActive; + buffer.Release (); + GameObject.Destroy (buffer); + + return tex; + } + static IEnumerator capture (ShipConstruct ship, string thumbName) { yield return null; - var savedScene = SceneManager.GetActiveScene (); - CraftThumbnail.TakeSnaphot (ship, 256, "thumbs", thumbName, - angles.x, angles.y, angles.z, angles.w, - fovFactor); + if (!thumbRig) { + // it died + yield break; + } + + var tex = takeSnapshot (ship); + var png = tex.EncodeToPNG (); + GameObject.Destroy (tex); + + string dir = KSPUtil.ApplicationRootPath + "thumbs/"; + string path = dir + thumbName + ".png"; + + if (!Directory.Exists (dir)) { + Directory.CreateDirectory (dir); + } + File.WriteAllBytes (path, png); + + Debug.Log ($"[ELCraftThumb] capture {path}"); + for (int i = ship.parts.Count; i-- > 0; ) { - UnityEngine.Object.Destroy (ship.parts[i].gameObject); + GameObject.Destroy (ship.parts[i].gameObject); } + + thumbRig.SetActive (false); } public static void Capture (ConfigNode craft, ELCraftType craftType, string craftFile) @@ -76,25 +171,37 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf if (ship.vesselDeltaV != null) { // The delta-v module is not needed. It has its own gameObject // for ShipConstruct. - UnityEngine.Object.Destroy (ship.vesselDeltaV.gameObject); + GameObject.Destroy (ship.vesselDeltaV.gameObject); ship.vesselDeltaV = null; } - // Need to keep the parts around for a few frames, but - // Part.FixedUpdate throws if things are not set up properly - // (which they won't be), but setting the state to PLACEMENT gets - // around this by tricking the part into thinking its being placed - // in the editor for (int i = ship.parts.Count; i-- > 0; ) { + // Need to keep the parts around for a few frames, but + // Part.FixedUpdate throws if things are not set up properly + // (which they won't be), but setting the state to PLACEMENT + // gets around this by tricking the part into thinking its + // being placed in the editor ship.parts[i].State = PartStates.PLACEMENT; + + // Make sure the part and main scene won't interact physcally + // or graphically (thumbLayer is chosen to be a layer that is + // not rendered by the scene cameras), and removing the + // colliders ensures that the parts can't collide with anything + EL_Utils.RemoveColliders (ship.parts[i].gameObject); + EL_Utils.SetLightMasks (ship.parts[i].gameObject, thumbMask); + EL_Utils.SetLayer (ship.parts[i].gameObject, thumbLayer, true); } if (craftType == ELCraftType.SPH) { - angles = new Vector4 (35, 135, 35, 135); + angles = new Vector2 (35, 135); } else { - angles = new Vector4 (45, 45, 45, 45); + angles = new Vector2 (45, 45); } string thumbName = UserThumbName (craftType, craftFile); + if (!thumbRig) { + CreateRig (); + } + thumbRig.SetActive (true); // Need to wait a frame for the parts to be renderable // (don't know why, but my guess is to give the various renderers // a chance to set themselves up) diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 7c1e03c3..8836d5aa 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -205,5 +205,32 @@ public static Sprite MakeSprite (Texture2D tex) return Sprite.Create (tex, rect, pivot, pixelsPerUnity, extrude, type, border); } + + public static void RemoveColliders (GameObject obj) + { + var colliders = obj.GetComponentsInChildren (); + for (int i = colliders.Length; i-- > 0; ) { + UnityEngine.Object.Destroy (colliders[i]); + } + } + + public static void SetLightMasks (GameObject obj, int mask) + { + var lights = obj.GetComponentsInChildren (); + for (int i = lights.Length; i-- > 0; ) { + lights[i].cullingMask = mask; + } + } + + public static void SetLayer (GameObject obj, int layer, bool recursive) + { + obj.layer = layer; + if (recursive) { + for (int i = obj.transform.childCount; i-- > 0; ) { + var child = obj.transform.GetChild (i).gameObject; + SetLayer (child, layer, true); + } + } + } } } From 8a8045adea5c68e4265ebee949a5351b7e36cc5f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 17:20:02 +0900 Subject: [PATCH 071/150] Manage thumbnail textures and sprites This should plug any leaks and takes care of the auto-updates. Need to fix the craft view thumbnail, though. --- Source/Makefile | 1 + Source/UI/CraftBrowser.cs | 2 +- Source/UI/CraftThumb.cs | 69 ++++++++++++----------- Source/UI/CraftThumbManager.cs | 100 +++++++++++++++++++++++++++++++++ Source/lib/Utils.cs | 8 +++ 5 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 Source/UI/CraftThumbManager.cs diff --git a/Source/Makefile b/Source/Makefile index eb3f7a16..f13bb5b9 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -71,6 +71,7 @@ EL_FILES := \ UI/CraftItem.cs \ UI/CraftItemView.cs \ UI/CraftThumb.cs \ + UI/CraftThumbManager.cs \ UI/CraftTypeSelector.cs \ UI/CraftView.cs \ UI/IResourceLine.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index 0686a373..d40262b7 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -199,7 +199,7 @@ public override void CreateUI () relativePath = ""; - craftThumb.Craft (ELCraftType.SubAss, ""); + craftThumb.Craft (""); craftItems = new ELCraftItem.List (craftGroup); craftItems.Content = craftList.Content; diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index 1d26928c..4095836e 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -29,14 +29,10 @@ namespace ExtraplanetaryLaunchpads { public class ELCraftThumb : UIImage { - static Texture2D genericCraftThumb; + ELCraftThumbManager.ThumbSprite thumbSprite; public override void CreateUI () { - if (!genericCraftThumb) { - genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); - } - base.CreateUI (); this.SizeDelta (256, 256) @@ -45,12 +41,6 @@ public override void CreateUI () ; } - protected override void OnDestroy () - { - Destroy (image.sprite); - base.OnDestroy (); - } - const int thumbLayer = 8; const int thumbMask = 1 << thumbLayer; const float thumbLightDist = 40; @@ -94,7 +84,7 @@ static void CreateRig () lightObj.transform.SetParent (thumbRig.transform, false); lightObj.transform.localPosition = tetraHedron[i] * thumbLightDist; lightObj.transform.localRotation = Quaternion.LookRotation (-tetraHedron[i], Vector3.up); - Debug.Log ($"[ELCraftThumb] CreateRig light {i} {lightObj.transform.localPosition} {lightObj.transform.forward}"); + //Debug.Log ($"[ELCraftThumb] CreateRig light {i} {lightObj.transform.localPosition} {lightObj.transform.forward}"); var light = lightObj.AddComponent (); light.cullingMask = thumbMask; @@ -133,7 +123,7 @@ static Texture2D takeSnapshot (ShipConstruct ship) return tex; } - static IEnumerator capture (ShipConstruct ship, string thumbName) + static IEnumerator capture (ShipConstruct ship, string thumbPath, bool savedHL) { yield return null; @@ -144,22 +134,26 @@ static IEnumerator capture (ShipConstruct ship, string thumbName) var tex = takeSnapshot (ship); var png = tex.EncodeToPNG (); - GameObject.Destroy (tex); - string dir = KSPUtil.ApplicationRootPath + "thumbs/"; - string path = dir + thumbName + ".png"; + string dir = KSPUtil.ApplicationRootPath; + string path = dir + thumbPath; + + if (!ELCraftThumbManager.UpdateThumbCache (thumbPath, tex)) { + GameObject.Destroy (tex); + } if (!Directory.Exists (dir)) { Directory.CreateDirectory (dir); } File.WriteAllBytes (path, png); - Debug.Log ($"[ELCraftThumb] capture {path}"); + //Debug.Log ($"[ELCraftThumb] capture {path}"); for (int i = ship.parts.Count; i-- > 0; ) { GameObject.Destroy (ship.parts[i].gameObject); } + HighLogic.LoadedSceneIsEditor = savedHL; thumbRig.SetActive (false); } @@ -168,6 +162,13 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf var ship = new ShipConstruct (); ship.LoadShip (craft); + // Need to keep the parts around for a few frames, but + // various modules throw if things are not set up properly (which + // they won't be), but tricking the parts and their modules into + // thinking they're being placed in the editor fixes things + bool savedHL = HighLogic.LoadedSceneIsEditor; + HighLogic.LoadedSceneIsEditor = true; + if (ship.vesselDeltaV != null) { // The delta-v module is not needed. It has its own gameObject // for ShipConstruct. @@ -175,11 +176,8 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf ship.vesselDeltaV = null; } for (int i = ship.parts.Count; i-- > 0; ) { - // Need to keep the parts around for a few frames, but - // Part.FixedUpdate throws if things are not set up properly - // (which they won't be), but setting the state to PLACEMENT - // gets around this by tricking the part into thinking its - // being placed in the editor + // See comment for HighLogic + ship.parts[i].ResumeState = PartStates.PLACEMENT; ship.parts[i].State = PartStates.PLACEMENT; // Make sure the part and main scene won't interact physcally @@ -187,6 +185,7 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf // not rendered by the scene cameras), and removing the // colliders ensures that the parts can't collide with anything EL_Utils.RemoveColliders (ship.parts[i].gameObject); + EL_Utils.SetLightMasks (ship.parts[i].gameObject, thumbMask); EL_Utils.SetLayer (ship.parts[i].gameObject, thumbLayer, true); } @@ -197,7 +196,7 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf angles = new Vector2 (45, 45); } - string thumbName = UserThumbName (craftType, craftFile); + string thumbPath = UserPath (craftType, craftFile); if (!thumbRig) { CreateRig (); } @@ -205,7 +204,7 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf // Need to wait a frame for the parts to be renderable // (don't know why, but my guess is to give the various renderers // a chance to set themselves up) - HighLogic.fetch.StartCoroutine (capture (ship, thumbName)); + HighLogic.fetch.StartCoroutine (capture (ship, thumbPath, savedHL)); } public static string UserThumbName (ELCraftType craftType, string craftFile) @@ -228,9 +227,10 @@ public static string UserPath (ELCraftType craftType, string craftFile) return $"thumbs/{UserThumbName (craftType, craftFile)}.png"; } + //FIXME remove public ELCraftThumb Craft (ELCraftType craftType, string craftFile) { - string saveDir = HighLogic.SaveFolder; + /*string saveDir = HighLogic.SaveFolder; string type = craftType.ToString (); string thumbName = Path.GetFileNameWithoutExtension(craftFile); string thumbPath = $"thumbs/{saveDir}_{type}_{thumbName}.png"; @@ -243,19 +243,24 @@ public ELCraftThumb Craft (ELCraftType craftType, string craftFile) EL_Utils.LoadImage (ref thumbTex, thumbPath); } Destroy (image.sprite); - image.sprite = EL_Utils.MakeSprite (thumbTex); + image.sprite = EL_Utils.MakeSprite (thumbTex);*/ return this; } - public ELCraftThumb Craft (string thumbPath) + void onSpriteUpdate (ELCraftThumbManager.ThumbSprite thumbSprite) { - var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; - bool ok = EL_Utils.LoadImage (ref thumbTex, thumbPath); - Debug.Log ($"[ELCraftThumb] Craft {thumbPath} {ok}"); - Destroy (image.sprite); - image.sprite = EL_Utils.MakeSprite (thumbTex); + image.sprite = thumbSprite.sprite; + } + public ELCraftThumb Craft (string thumbPath) + { + if (thumbSprite != null) { + thumbSprite.onUpdate.RemoveListener (onSpriteUpdate); + } + thumbSprite = ELCraftThumbManager.GetThumb (thumbPath); + thumbSprite.onUpdate.AddListener (onSpriteUpdate); + image.sprite = thumbSprite.sprite; return this; } } diff --git a/Source/UI/CraftThumbManager.cs b/Source/UI/CraftThumbManager.cs new file mode 100644 index 00000000..a2c0a395 --- /dev/null +++ b/Source/UI/CraftThumbManager.cs @@ -0,0 +1,100 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftThumbManager : UIImage + { + public class ThumbSprite + { + Sprite _sprite; + public Sprite sprite + { + get { return _sprite; } + set { + _sprite = value; + onUpdate.Invoke (this); + } + } + + public class ThumbEvent : UnityEvent { } + public ThumbEvent onUpdate { get; private set; } + + public ThumbSprite (Sprite sprite) + { + _sprite = sprite; + onUpdate = new ThumbEvent (); + } + } + + static Texture2D genericCraftThumb; + + static Dictionary thumbnailCache = new Dictionary (); + public static ThumbSprite GetThumb (string thumbPath) + { + // FIXME use new icon :) + if (!genericCraftThumb) { + genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); + } + + ThumbSprite thumb; + if (thumbnailCache.TryGetValue (thumbPath, out thumb) && thumb.sprite ) { + return thumb; + } + + var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; + bool ok = EL_Utils.LoadImage (ref thumbTex, thumbPath); + Debug.Log ($"[ELCraftThumbManager] GetThumb {thumbPath} {ok}"); + var sprite = EL_Utils.MakeSprite (thumbTex); + + if (thumb == null) { + thumb = new ThumbSprite (sprite); + } else { + thumb.sprite = sprite; + } + + thumbnailCache[thumbPath] = thumb; + return thumb; + } + + public static bool UpdateThumbCache (string thumbPath, Texture2D tex) + { + ThumbSprite thumb; + tex.Apply (); + Debug.Log ($"[ELCraftThumbManager] UpdateThumbCache {thumbPath} {tex}"); + if (thumbnailCache.TryGetValue (thumbPath, out thumb)) { + Debug.Log ($" update"); + GameObject.Destroy (thumb.sprite.texture); + GameObject.Destroy (thumb.sprite); + thumb.sprite = EL_Utils.MakeSprite (tex); + return true; + } + Debug.Log ($" new"); + return false; + } + } +} diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 8836d5aa..79161afb 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -214,6 +214,14 @@ public static void RemoveColliders (GameObject obj) } } + public static void DisableModules (GameObject obj) + { + var modules = obj.GetComponentsInChildren (); + for (int i = modules.Length; i-- > 0; ) { + modules[i].enabled = false; + } + } + public static void SetLightMasks (GameObject obj, int mask) { var lights = obj.GetComponentsInChildren (); From ea3da344aa3244d272f36b8d08ceccdf1c05f656 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 17:34:20 +0900 Subject: [PATCH 072/150] Rewrite the guessing thumb loader In the end, I didn't want to store the thumb path in the build control. With this, if the thumbnail exists, then it is used, but if it doesn't, it is assumed to be a user craft thumbnail. Fixes the craft view thumbnail and its auto-update. --- Source/UI/CraftThumb.cs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index 4095836e..dd1a4cdf 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -227,25 +227,27 @@ public static string UserPath (ELCraftType craftType, string craftFile) return $"thumbs/{UserThumbName (craftType, craftFile)}.png"; } - //FIXME remove + static string applicationRoot; + public ELCraftThumb Craft (ELCraftType craftType, string craftFile) { - /*string saveDir = HighLogic.SaveFolder; - string type = craftType.ToString (); - string thumbName = Path.GetFileNameWithoutExtension(craftFile); - string thumbPath = $"thumbs/{saveDir}_{type}_{thumbName}.png"; - - var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; - if (!EL_Utils.LoadImage (ref thumbTex, thumbPath) - && (craftType == ELCraftType.VAB - || craftType == ELCraftType.SPH)) { - thumbPath = $"Ships/@thumbs/{type}/{thumbName}.png"; - EL_Utils.LoadImage (ref thumbTex, thumbPath); + if (applicationRoot == null) { + applicationRoot = KSPUtil.ApplicationRootPath.Replace("\\", "/"); } - Destroy (image.sprite); - image.sprite = EL_Utils.MakeSprite (thumbTex);*/ + string thumbPath = UserPath (craftType, craftFile); - return this; + if (File.Exists (applicationRoot + thumbPath)) { + return Craft (thumbPath); + } + + string stockPath = StockPath (craftType, craftFile); + if (File.Exists (applicationRoot + stockPath)) { + return Craft (stockPath); + } + + // assume it's user craft and we can generate the thumb, it will + // be updated if the thumb is generated + return Craft (thumbPath); } void onSpriteUpdate (ELCraftThumbManager.ThumbSprite thumbSprite) From 8db06c9e5b79851a41c9666fd8340e554f8ad27d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 18:31:05 +0900 Subject: [PATCH 073/150] Use JadeOfMaar's icon for the default thumbnail --- Assets/Makefile | 6 +++++- Source/UI/CraftThumbManager.cs | 15 +++++++++------ Source/lib/Utils.cs | 8 ++++++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Assets/Makefile b/Assets/Makefile index 608b06e0..11700303 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -25,6 +25,7 @@ FLAGS := \ nightheron.png MISC := \ + ELGenericCraftThumb.png \ kairyuu_scaled.png \ plaque.png @@ -71,6 +72,9 @@ icon_filter_n.png: icon_button.svg icon_filter_s.png: icon_button.svg sed -e 's/\#....../#ffffff/g' $^ | inkscape --export-width=32 --export-height=32 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ /dev/stdin +ELGenericCraftThumb.png: EL_UntitledSpacecraft.svg + inkscape --export-width=256 --export-height=256 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ + clean: rm -f kairyuu.png kairyuu_scaled.png icon_button.png icon_filter*.png ${GUI_ICONS} @@ -79,7 +83,7 @@ install: all cp kairyuu.png kairyuu_scaled.png ${MODGAMEDATA}/Agencies cp nightheron.png ${MODGAMEDATA}/Flags mkdir -p ${MODGAMEDATA}/Textures - cp icon_button.png icon_filter*.png plaque.png ${MODGAMEDATA}/Textures + cp ELGenericCraftThumb.png icon_button.png icon_filter*.png plaque.png ${MODGAMEDATA}/Textures #cp ${GUI_ICONS} ${MODGAMEDATA}/Textures .PHONY: all clean install diff --git a/Source/UI/CraftThumbManager.cs b/Source/UI/CraftThumbManager.cs index a2c0a395..15afce71 100644 --- a/Source/UI/CraftThumbManager.cs +++ b/Source/UI/CraftThumbManager.cs @@ -51,14 +51,21 @@ public ThumbSprite (Sprite sprite) } } + static string GenericThumbName = "GameData/ExtraplanetaryLaunchpads/Textures/ELGenericCraftThumb.png"; static Texture2D genericCraftThumb; static Dictionary thumbnailCache = new Dictionary (); public static ThumbSprite GetThumb (string thumbPath) { - // FIXME use new icon :) if (!genericCraftThumb) { - genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); + if (EL_Utils.KSPFileExists (GenericThumbName)) { + var tex = new Texture2D (256, 256, TextureFormat.ARGB32, false); + EL_Utils.LoadImage (ref tex, GenericThumbName); + genericCraftThumb = tex; + } else { + // ick, but better than nothing + genericCraftThumb = AssetBase.GetTexture("craftThumbGeneric"); + } } ThumbSprite thumb; @@ -68,7 +75,6 @@ public static ThumbSprite GetThumb (string thumbPath) var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; bool ok = EL_Utils.LoadImage (ref thumbTex, thumbPath); - Debug.Log ($"[ELCraftThumbManager] GetThumb {thumbPath} {ok}"); var sprite = EL_Utils.MakeSprite (thumbTex); if (thumb == null) { @@ -85,15 +91,12 @@ public static bool UpdateThumbCache (string thumbPath, Texture2D tex) { ThumbSprite thumb; tex.Apply (); - Debug.Log ($"[ELCraftThumbManager] UpdateThumbCache {thumbPath} {tex}"); if (thumbnailCache.TryGetValue (thumbPath, out thumb)) { - Debug.Log ($" update"); GameObject.Destroy (thumb.sprite.texture); GameObject.Destroy (thumb.sprite); thumb.sprite = EL_Utils.MakeSprite (tex); return true; } - Debug.Log ($" new"); return false; } } diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 79161afb..573528b6 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -179,6 +179,14 @@ public static bool PrintIngredient (StringBuilder sb, Ingredient ingredient, str } static string applicationRoot; + public static bool KSPFileExists (string filename) + { + if (applicationRoot == null) { + applicationRoot = KSPUtil.ApplicationRootPath.Replace("\\", "/"); + } + return File.Exists (applicationRoot + filename); + } + public static bool LoadImage (ref Texture2D tex, string filename) { if (applicationRoot == null) { From f52afeeec5f51f2508c5e961a47e52c4f37b5b0f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 18:56:46 +0900 Subject: [PATCH 074/150] Close craft browser when scene changes --- Source/UI/CraftBrowser.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index d40262b7..64d1df75 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -329,6 +329,22 @@ bool ScanDirectory (ELCraftType type, bool stock, string path) return true; } + protected override void Awake () + { + GameEvents.onGameSceneSwitchRequested.Add (onGameSceneSwitchRequested); + } + + protected override void OnDestroy () + { + GameEvents.onGameSceneSwitchRequested.Remove (onGameSceneSwitchRequested); + } + + void onGameSceneSwitchRequested(GameEvents.FromToAction data) + { + // scene change is effectively Cancel :) + Cancel (); + } + static ELCraftBrowser craftBrowser; public static void OpenDialog (ELCraftType craftType, string path, From 1d77fc0c2d1f70b70dca1677f9d179054a2bb68f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 23:01:41 +0900 Subject: [PATCH 075/150] Move the build and resource manager views into tabs Much less clutter :) --- KodeUI | 2 +- Source/UI/BuildManagerView.cs | 10 +++++++++- Source/UI/Localization.cs | 2 ++ Source/UI/MainWindow.cs | 18 ++++++++++++++++++ Source/UI/ResourceManagerView.cs | 10 +++++++++- 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/KodeUI b/KodeUI index e4ac322e..90c2bfba 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit e4ac322e5fd09675e31241bd278e5f87158389be +Subproject commit 90c2bfbaba457feade21627927fbc02e0b9e9642 diff --git a/Source/UI/BuildManagerView.cs b/Source/UI/BuildManagerView.cs index 2bc3e18a..20844836 100644 --- a/Source/UI/BuildManagerView.cs +++ b/Source/UI/BuildManagerView.cs @@ -19,7 +19,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELBuildManagerView : Layout + public class ELBuildManagerView : Layout, TabController.ITabItem { ELStatusBar statusBar; ELPadView padView; @@ -71,5 +71,13 @@ public void SetControl (ELBuildControl control) statusBar.SetVessel (control.builder.vessel); padView.SetControl (control); } +#region TabController.ITabItem + public string TabName { get { return ELLocalization.BuildManager; } } + public bool TabEnabled { get { return padView.control != null; } } + public void SetTabVisible (bool visible) + { + SetActive (visible); + } +#endregion } } diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 49718ae0..0b65e88b 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -20,6 +20,8 @@ namespace ExtraplanetaryLaunchpads { public static class ELLocalization { + public static string BuildManager { get; } = "Build Manager"; + public static string ResourceManager { get; } = "Resource Manager"; public static string Productivity { get; } = "Productivity:"; public static string SelectCraft { get; } = "Select Craft"; public static string SelectedCraft { get; } = "Selected Craft"; diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index 3107ca3f..abee16f3 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -15,12 +15,15 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ +using System.Collections.Generic; + using KodeUI; namespace ExtraplanetaryLaunchpads { public class ELMainWindow : Window { + TabController tabController; ELBuildManagerView buildManager; ELResourceManagerView resourceManager; @@ -37,11 +40,24 @@ public override void CreateUI() .Pivot(PivotPresets.TopLeft) .PreferredWidth(695) + .Add (out tabController) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand(false,false) + .FlexibleLayout (true, false) + .Finish () + .Add (out buildManager) .Finish () .Add (out resourceManager) .Finish () .Finish(); + + var tabItems = new List () { + buildManager, + resourceManager, + }; + tabController.Items (tabItems); } public override void Style () @@ -53,11 +69,13 @@ public void SetVessel (Vessel vessel) { buildManager.SetVessel (vessel); resourceManager.SetVessel (vessel); + tabController.UpdateTabStates (); } public void SetControl (ELBuildControl control) { buildManager.SetControl (control); + tabController.UpdateTabStates (); } public void SetVisible (bool visible) diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs index 12521f1d..bb2df901 100644 --- a/Source/UI/ResourceManagerView.cs +++ b/Source/UI/ResourceManagerView.cs @@ -24,7 +24,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELResourceManagerView : Layout + public class ELResourceManagerView : Layout, TabController.ITabItem { ResourceGroup.List resourceGroups; ResourceGroup.Dict resourceGroupDict; @@ -190,5 +190,13 @@ public void SetVessel (Vessel vessel) onTransferableChanged (); RebuildResources (manager); } +#region TabController.ITabItem + public string TabName { get { return ELLocalization.ResourceManager; } } + public bool TabEnabled { get { return resourceGroups.Count > 0; } } + public void SetTabVisible (bool visible) + { + SetActive (visible); + } +#endregion } } From a11d22aa3d02fcef05a988167a6cfe636151543b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 10 Oct 2020 23:08:50 +0900 Subject: [PATCH 076/150] Fix asset cleaning --- Assets/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Makefile b/Assets/Makefile index 11700303..2ff8491f 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -76,7 +76,7 @@ ELGenericCraftThumb.png: EL_UntitledSpacecraft.svg inkscape --export-width=256 --export-height=256 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ clean: - rm -f kairyuu.png kairyuu_scaled.png icon_button.png icon_filter*.png ${GUI_ICONS} + rm -f ${ICONS} ${FLAGS} ${MISC} ${GUI_ICONS} install: all mkdir -p ${MODGAMEDATA}/Agencies ${MODGAMEDATA}/Flags From 5756dccadd0340fe48d309b78732d2e8caad7a23 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 11 Oct 2020 11:10:54 +0900 Subject: [PATCH 077/150] New app and filter icons from JadeOfMaar Based on EL_UntitledSpacecraft. There are some minor issues with the app icon's svg (fix coming) --- Assets/EL_app.svg | 1 + Assets/EL_filter.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 Assets/EL_app.svg create mode 100644 Assets/EL_filter.svg diff --git a/Assets/EL_app.svg b/Assets/EL_app.svg new file mode 100644 index 00000000..1008a9fd --- /dev/null +++ b/Assets/EL_app.svg @@ -0,0 +1 @@ +EL_appEL \ No newline at end of file diff --git a/Assets/EL_filter.svg b/Assets/EL_filter.svg new file mode 100644 index 00000000..9bfb9793 --- /dev/null +++ b/Assets/EL_filter.svg @@ -0,0 +1 @@ +EL_filterEL \ No newline at end of file From c0e50d87069d98d08294720518700b5bfeaaabc3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 11 Oct 2020 11:16:11 +0900 Subject: [PATCH 078/150] Fixed app icon from JadeOfMaar Still needs a little tweaking on the sky, but I think I can handle that myself :) --- Assets/EL_app.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/EL_app.svg b/Assets/EL_app.svg index 1008a9fd..dd1537e9 100644 --- a/Assets/EL_app.svg +++ b/Assets/EL_app.svg @@ -1 +1 @@ -EL_appEL \ No newline at end of file +EL_appEL \ No newline at end of file From 4a16835c24becce30dfcb5c3b1556624bb5b695a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 11 Oct 2020 12:07:16 +0900 Subject: [PATCH 079/150] Switch to the new app and filter icons --- Assets/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Assets/Makefile b/Assets/Makefile index 2ff8491f..c58bac53 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -63,14 +63,14 @@ nightheron.png: nightheron.svg kairyuu_scaled.png: kairyuu.svg inkscape --export-width=64 --export-height=40 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ -icon_button.png: icon_button.svg - inkscape --export-width=24 --export-height=24 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ +icon_button.png: EL_app.svg + inkscape --export-width=38 --export-height=38 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ -icon_filter_n.png: icon_button.svg - sed -e 's/\#....../#000000/g' $^ | inkscape --export-width=32 --export-height=32 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ /dev/stdin +icon_filter_n.png: EL_filter.svg + sed -e 's/\#[[:xdigit:]]\{6\}/#000000/g' -e 's/\#[[:xdigit:]]\{3\}/#000/g' $^ | inkscape --export-width=32 --export-height=32 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ /dev/stdin -icon_filter_s.png: icon_button.svg - sed -e 's/\#....../#ffffff/g' $^ | inkscape --export-width=32 --export-height=32 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ /dev/stdin +icon_filter_s.png: EL_filter.svg + sed -e 's/\#[[:xdigit:]]\{6\}/#ffffff/g' -e 's/\#[[:xdigit:]]\{3\}/#fff/g' $^ | inkscape --export-width=32 --export-height=32 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ /dev/stdin ELGenericCraftThumb.png: EL_UntitledSpacecraft.svg inkscape --export-width=256 --export-height=256 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ From d78d095a1988bfcbbf4d628fe2c3b1e3106f40e5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 11 Oct 2020 17:10:00 +0900 Subject: [PATCH 080/150] Make empty thumb path always the generic thumb --- Source/UI/CraftThumbManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/UI/CraftThumbManager.cs b/Source/UI/CraftThumbManager.cs index 15afce71..ed646bb2 100644 --- a/Source/UI/CraftThumbManager.cs +++ b/Source/UI/CraftThumbManager.cs @@ -74,7 +74,9 @@ public static ThumbSprite GetThumb (string thumbPath) } var thumbTex = GameObject.Instantiate (genericCraftThumb) as Texture2D; - bool ok = EL_Utils.LoadImage (ref thumbTex, thumbPath); + if (!String.IsNullOrEmpty (thumbPath)) { + EL_Utils.LoadImage (ref thumbTex, thumbPath); + } var sprite = EL_Utils.MakeSprite (thumbTex); if (thumb == null) { From b152356b132c28dee385dcd5b91bda01422a9e6d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 13 Oct 2020 13:10:57 +0900 Subject: [PATCH 081/150] Get the part selector mostly up and running Can't actually select a part yet, category icons need a lot of work (and tooltips), and no info is displayed, but the fundamentals are there. However, there's a problem with the part icons showing behind other UI windows that are behind the craft browser. Not sure if the problem is in Unity, KSP or just my setup (it's entirely possible the problem is there in the editor, just not noticeable because there are no cousin UI elements behind the parts list). --- KodeUI | 2 +- Source/Makefile | 1 + Source/UI/CraftBrowser.cs | 19 +- Source/UI/PartSelector.cs | 545 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 562 insertions(+), 5 deletions(-) create mode 100644 Source/UI/PartSelector.cs diff --git a/KodeUI b/KodeUI index 90c2bfba..8855a7ad 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 90c2bfbaba457feade21627927fbc02e0b9e9642 +Subproject commit 8855a7adc227b93f1504afdbc3118e614a9a780b diff --git a/Source/Makefile b/Source/Makefile index f13bb5b9..10b89c0b 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -81,6 +81,7 @@ EL_FILES := \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ + UI/PartSelector.cs \ UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ UI/ResourceGroup.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index 64d1df75..e587f64f 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -59,6 +59,7 @@ public delegate void SelectFileCallback(string fullPath, public ELCraftType craftType { get; private set; } ELCraftTypeSelector typeSelector; + ELPartSelector partSelector; ScrollView craftList; ELCraftThumb craftThumb; ScrollView craftInfo; @@ -89,7 +90,7 @@ public override void CreateUI () { base.CreateUI (); - UIScrollbar list_scrollbar; + UIScrollbar craftList_scrollbar; UIScrollbar info_scrollbar; this.Title (ELLocalization.SelectCraft) @@ -108,6 +109,9 @@ public override void CreateUI () .ControlChildSize (true, true) .ChildForceExpand (false,false) + .Add (out partSelector) + .PreferredSize (321, -1) + .Finish () .Add (out craftList) .Horizontal (false) .Vertical (true) @@ -115,7 +119,7 @@ public override void CreateUI () .ControlChildSize (true, true) .ChildForceExpand (false, true) .PreferredSize (321, -1) - .Add (out list_scrollbar, "Scrollbar") + .Add (out craftList_scrollbar, "Scrollbar") .Direction(Scrollbar.Direction.BottomToTop) .PreferredWidth (15) .Finish () @@ -169,7 +173,7 @@ public override void CreateUI () .Finish () .Finish (); - craftList.VerticalScrollbar = list_scrollbar; + craftList.VerticalScrollbar = craftList_scrollbar; craftList.Viewport.FlexibleLayout (true, true); craftList.Content .Vertical () @@ -279,7 +283,14 @@ void SetRelativePath (ELCraftType craftType, bool stock, string path) SetActive (true); this.craftType = craftType; relativePath = path; - ScanDirectory (craftType, stock, path); + if (craftType == ELCraftType.Part) { + partSelector.SetVisible (true); + craftList.SetActive (false); + } else { + partSelector.SetVisible (false); + craftList.SetActive (true); + ScanDirectory (craftType, stock, path); + } } bool ScanDirectory (ELCraftType type, bool stock, string path) diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs new file mode 100644 index 00000000..8218519a --- /dev/null +++ b/Source/UI/PartSelector.cs @@ -0,0 +1,545 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + using TTC = KSP.UI.Screens.Editor.PartListTooltipController; + + public class ELPartSelector : Layout + { + static PartCategories []categoryOrder = { + PartCategories.Pods, + PartCategories.FuelTank, + PartCategories.Engine, + PartCategories.Control, + PartCategories.Structural, + PartCategories.Robotics, + PartCategories.Coupling, + PartCategories.Payload, + PartCategories.Aero, + PartCategories.Ground, + PartCategories.Thermal, + PartCategories.Electrical, + PartCategories.Communication, + PartCategories.Science, + PartCategories.Cargo, + PartCategories.Utility, + PartCategories.none, + }; + +#region ELPartCategory + class ELPartCategory + { + public delegate void CategorySelectedCallback (PartCategories category); + public CategorySelectedCallback CategorySelected; + public Sprite onIcon { get; private set; } + public Sprite offIcon { get; private set; } + public PartCategories category { get; private set; } + + static Sprite []elFilterSprites = new Sprite[2]; + static string []elFilterNames = { + "icon_filter_n", + "icon_filter_s" + }; + + static Sprite FindSprite (PartCategories category, bool on) + { + int ind = on ? 1 : 0; + if (elFilterSprites[ind] == null) { + string path = $"GameData/ExtraplanetaryLaunchpads/Textures/{elFilterNames[ind]}.png"; + var tex = new Texture2D (32, 32, TextureFormat.ARGB32, false); + bool ok = EL_Utils.LoadImage (ref tex, path); + elFilterSprites[ind] = EL_Utils.MakeSprite (tex); + Debug.Log ($"[ELPartCategory] FindSprite {category} {path} {ok}"); + } + return elFilterSprites[ind]; + } + + public ELPartCategory (PartCategories category) + { + Debug.Log ($"[ELPartCategory] {category}"); + this.category = category; + onIcon = FindSprite (category, true); + offIcon = FindSprite (category, false); + } + + public void Select () + { + CategorySelected (category); + } + +#region ELPartCategory.List + public class List : List, UIKit.IListObject + { + ToggleGroup group; + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Group (group) + .Category (this[index]) + .DebugLayout () + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var view = obj.GetComponent (); + view.Category (this[index]); + } + + public List (ToggleGroup group) + { + this.group = group; + } + + public void Select (int index) + { + if (index >= 0 && index < Count) { + group.SetAllTogglesOff (false); + var child = Content.rectTransform.GetChild (index); + var view = child.GetComponent (); + view.Select (); + } + } + } +#endregion + } +#endregion + +#region ELPartCategoryView + class ELPartCategoryView : UIObject, ILayoutElement + { + Toggle toggle; + Image image; + UIImage icon; + + ELPartCategory category; + + public override void CreateUI () + { + image = gameObject.AddComponent (); + image.type = UnityEngine.UI.Image.Type.Sliced; + + this.PreferredSize (32, 32) + .Add (out icon) + .Anchor (AnchorPresets.StretchAll) + .Pivot (PivotPresets.MiddleCenter) + .SizeDelta(0, 0) + .Finish () + ; + + toggle = gameObject.AddComponent (); + toggle.onValueChanged.AddListener (onValueChanged); + toggle.targetGraphic = image; + toggle.graphic = icon.image; + } + + public override void Style () + { + image.sprite = style.sprite; + image.color = style.color ?? UnityEngine.Color.white; + + toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; + toggle.transition = Selectable.Transition.ColorTint; + } + + void onValueChanged (bool on) + { + if (on) { + Select (); + } + } + + public void Select () + { + category.Select (); + } + + public ELPartCategoryView Group (ToggleGroup group) + { + toggle.group = group; + return this; + } + + public ELPartCategoryView Category (ELPartCategory category) + { + this.category = category; + image.sprite = category.offIcon; + style.sprite = image.sprite; + icon.image.sprite = category.onIcon; + return this; + } + +#region ILayoutElement + Vector2 minSize; + Vector2 preferredSize; + + public void CalculateLayoutInputHorizontal() + { + minSize = Vector2.zero; + float i, s; + i = image.preferredWidth; + s = icon.image.preferredWidth; + preferredSize.x = Mathf.Max (i, s); + } + + public void CalculateLayoutInputVertical() + { + float i, s; + i = image.preferredHeight; + s = icon.image.preferredHeight; + preferredSize.y = Mathf.Max (i, s); + } + + public int layoutPriority { get { return 0; } } + public float minWidth { get { return minSize.x; } } + public float preferredWidth { get { return preferredSize.x; } } + public float flexibleWidth { get { return -1; } } + public float minHeight { get { return minSize.y; } } + public float preferredHeight { get { return preferredSize.y; } } + public float flexibleHeight { get { return -1; } } +#endregion + } +#endregion + +#region ELPartItemView + class ELPartItemView : UIObject + { + AvailablePart availablePart; + Image background; + Toggle toggle; + GameObject partIcon; + + public Material []materials; + + public override void CreateUI () + { + background = gameObject.AddComponent (); + background.type = UnityEngine.UI.Image.Type.Sliced; + + toggle = gameObject.AddComponent (); + toggle.targetGraphic = background; + + this.Pivot (PivotPresets.MiddleCenter); + } + + public override void Style () + { + background.sprite = style.sprite; + background.color = style.color ?? UnityEngine.Color.white; + + toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; + toggle.transition = style.transition ?? Selectable.Transition.ColorTint; + if (style.stateSprites.HasValue) { + toggle.spriteState = style.stateSprites.Value; + } + } + + public ELPartItemView Group (ToggleGroup group) + { + toggle.group = group; + return this; + } + + protected override void OnDestroy () + { + Destroy (partIcon); + } + + public ELPartItemView OnValueCanged (UnityAction action) + { + toggle.onValueChanged.AddListener (action); + return this; + } + + static Material []CollectMaterials (GameObject obj) + { + var materials = new List (); + var renderers = obj.GetComponentsInChildren (); + for (int i = renderers.Length; i-- > 0; ) { + var mats = renderers[i].materials; + for (int j = mats.Length; j-- > 0; ) { + if (!mats[j].HasProperty (PropertyIDs._MinX)) { + continue; + } + materials.Add (mats[j]); + } + } + return materials.ToArray (); + } + + public ELPartItemView AvailablePart (AvailablePart availablePart) + { + if (partIcon) { + Destroy (partIcon); + } + this.availablePart = availablePart; + partIcon = GameObject.Instantiate (availablePart.iconPrefab); + partIcon.transform.SetParent (rectTransform, false); + partIcon.transform.localPosition = new Vector3 (0, 0, -39); + partIcon.transform.localScale = new Vector3 (39, 39, 39); + var rot = Quaternion.Euler (-15, 0, 0); + rot = rot * Quaternion.Euler (0, -30, 0); + partIcon.transform.rotation = rot; + partIcon.SetActive(true); + int layer = LayerMask.NameToLayer ("UIAdditional"); + EL_Utils.SetLayer (partIcon, layer, true); + materials = CollectMaterials (partIcon); + return this; + } + } +#endregion + +#region ELPartList + class ELPartList : List, UIKit.IListObject + { + ToggleGroup group; + + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Group (group) + .OnValueCanged (on => select (index, on)) + .AvailablePart (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var item = obj.GetComponent (); + item.AvailablePart (this[index]); + } + + public ELPartList (ToggleGroup group) + { + this.group = group; + } + + void select (int index, bool on) + { + if (on) { + var ap = this[index]; + Debug.Log ($"[ELPartList] select {index}i {ap.iconScale}"); + EL_Utils.dumpxform (ap.iconPrefab.transform, false); + } + } + } +#endregion + + ScrollView categoryView; + ScrollView partListView; + ELPartList partList; + ELPartCategory.List categoryList; + + class APList : List { } + class CategoryDict : Dictionary { } + CategoryDict partCategories; + + public override void CreateUI () + { + base.CreateUI (); + + UIScrollbar part_scrollbar; + + this.Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Add (out categoryView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .Finish () + .Add (out partListView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout (true, true) + .Add (out part_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + ; + + ToggleGroup categoryGroup; + categoryView.Viewport.PreferredSize (32, -1); + categoryView.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .ToggleGroup (out categoryGroup) + .Finish (); + + categoryList = new ELPartCategory.List (categoryGroup); + categoryList.Content = categoryView.Content; + + ToggleGroup partGroup; + partListView.VerticalScrollbar = part_scrollbar; + partListView.Viewport.FlexibleLayout (true, true); + partListView.Content + .Grid () + .Spacing (2) + .Padding (2) + .StartCorner (GridLayoutGroup.Corner.UpperLeft) + .StartAxis (GridLayoutGroup.Axis.Horizontal) + .CellSize (64, 64) + .Constraint (GridLayoutGroup.Constraint.FixedColumnCount) + .ConstraintCount (3) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter (true, false) + .SizeDelta (0, 0) + .ToggleGroup (out partGroup) + .Finish (); + partListView.ScrollRect.onValueChanged.AddListener (onPartListUpdate); + + partList = new ELPartList (partGroup); + partList.Content = partListView.Content; + CreateLight (partListView.transform); + } + + void CreateLight (Transform parent) + { + var lightObj = new GameObject ("ELPartList light"); + lightObj.transform.SetParent (parent, false); + + var light = lightObj.AddComponent (); + light.type = LightType.Directional; + light.intensity = 0.5f; + light.colorTemperature = 6570; + light.cullingMask = 0x2000020; + } + + void onPartListUpdate (Vector2 pos) + { + TTC.SetupScreenSpaceMask (partListView.Viewport.rectTransform); + + var parts = partListView.Content.rectTransform; + for (int i = parts.childCount; i-- > 0; ) { + var item = parts.GetChild (i).GetComponent (); + TTC.SetScreenSpaceMaskMaterials (item.materials); + } + } + + public override void Style () + { + } + + void CategorySelected (PartCategories category) + { + var available = partCategories[category]; + partList.Clear (); + for (int i = 0; i < available.Count; i++) { + var ap = available[i]; + if (ResearchAndDevelopment.PartTechAvailable (ap)) { + partList.Add (ap); + } + } + UIKit.UpdateListContent (partList); + } + + void BuildCategories () + { + partCategories = new CategoryDict (); + for (int i = categoryOrder.Length; i-- > 0; ) { + partCategories[categoryOrder[i]] = new APList (); + } + for (int i = PartLoader.LoadedPartsList.Count; i-- > 0; ) { + var ap = PartLoader.LoadedPartsList[i]; + var cat = ap.category; + if (cat == PartCategories.none) { + if (ap.TechRequired == "Unresearcheable") { + continue; + } + } else if (cat == PartCategories.Propulsion) { + if (ap.moduleInfos.Exists (p => p.moduleName == "Engine")) { + cat = PartCategories.Engine; + } else { + cat = PartCategories.FuelTank; + } + } + partCategories[cat].Add (ap); + } + for (int i = categoryOrder.Length; i-- > 0; ) { + partCategories[categoryOrder[i]].Sort ((a, b) => a.title.CompareTo(b.title)); + } + } + + public void SetVisible (bool visible) + { + SetActive (visible); + if (visible) { + if (partCategories == null) { + BuildCategories (); + } + categoryList.Clear (); + for (int i = 0; i < categoryOrder.Length; i++) { + var category = categoryOrder[i]; + if (partCategories[category].Count > 0) { + var cat = new ELPartCategory (category); + cat.CategorySelected = CategorySelected; + categoryList.Add (cat); + } + } + Debug.Log ($"[ELPartSelector] SetVisible {categoryList.Count}"); + UIKit.UpdateListContent (categoryList); + } else { + partList.Clear (); + UIKit.UpdateListContent (partList); + } + } + } +} From 9d7332d90d1744d02966cb0a12f03bbac392f74a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 13 Oct 2020 13:29:05 +0900 Subject: [PATCH 082/150] Rename CraftView to BuildCraftView Slightly better naming consistency. --- Source/Makefile | 2 +- Source/UI/{CraftView.cs => BuildCraftView.cs} | 2 +- Source/UI/BuildManagerView.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename Source/UI/{CraftView.cs => BuildCraftView.cs} (99%) diff --git a/Source/Makefile b/Source/Makefile index 10b89c0b..345a02d9 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -73,7 +73,7 @@ EL_FILES := \ UI/CraftThumb.cs \ UI/CraftThumbManager.cs \ UI/CraftTypeSelector.cs \ - UI/CraftView.cs \ + UI/BuildCraftView.cs \ UI/IResourceLine.cs \ UI/Localization.cs \ UI/MainWindow.cs \ diff --git a/Source/UI/CraftView.cs b/Source/UI/BuildCraftView.cs similarity index 99% rename from Source/UI/CraftView.cs rename to Source/UI/BuildCraftView.cs index 28815dd9..0036e702 100644 --- a/Source/UI/CraftView.cs +++ b/Source/UI/BuildCraftView.cs @@ -30,7 +30,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELCraftView : Layout + public class ELBuildCraftView : Layout { class RequiredResource : IResourceLine { diff --git a/Source/UI/BuildManagerView.cs b/Source/UI/BuildManagerView.cs index 20844836..f6763de1 100644 --- a/Source/UI/BuildManagerView.cs +++ b/Source/UI/BuildManagerView.cs @@ -23,7 +23,7 @@ public class ELBuildManagerView : Layout, TabController.ITabItem { ELStatusBar statusBar; ELPadView padView; - ELCraftView craftView; + ELBuildCraftView craftView; ELBuildView buildView; ELTransferView transferView; @@ -39,7 +39,7 @@ public override void CreateUI() .Finish() .Add(out padView, "PadView") .Finish() - .Add(out craftView, "CraftView") + .Add(out craftView, "BuildCraftView") .Finish() .Add(out buildView, "BuildView") .Finish() From 5e5e02d7e08663652332b43073fec72f731c4530 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 14 Oct 2020 14:05:30 +0900 Subject: [PATCH 083/150] Split the craft selector out from the browser Makes switching between craft and parts easier. --- Source/Makefile | 1 + Source/UI/CraftBrowser.cs | 274 +++++-------------------------- Source/UI/CraftSelector.cs | 289 +++++++++++++++++++++++++++++++++ Source/UI/CraftTypeSelector.cs | 16 +- Source/UI/PartSelector.cs | 29 +++- 5 files changed, 368 insertions(+), 241 deletions(-) create mode 100644 Source/UI/CraftSelector.cs diff --git a/Source/Makefile b/Source/Makefile index 345a02d9..0358c73b 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -70,6 +70,7 @@ EL_FILES := \ UI/CraftBrowser.cs \ UI/CraftItem.cs \ UI/CraftItemView.cs \ + UI/CraftSelector.cs \ UI/CraftThumb.cs \ UI/CraftThumbManager.cs \ UI/CraftTypeSelector.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index e587f64f..f5ddce87 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -34,65 +34,26 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { public enum ELCraftType { VAB, SPH, SubAss, Part }; + public delegate void SelectFileCallback(string fullPath, + ELCraftType craftType); + public delegate void CancelledCallback(); public class ELCraftBrowser : Window { - public delegate void SelectFileCallback(string fullPath, - ELCraftType craftType); - public SelectFileCallback OnFileSelected; - - public delegate void CancelledCallback(); - public CancelledCallback OnBrowseCancelled; - - static EditorFacility []craftFacility = new EditorFacility[] { - EditorFacility.VAB, - EditorFacility.SPH, - EditorFacility.None, - }; - - static ELCraftType []facilityType = new ELCraftType[] { - ELCraftType.SubAss, - ELCraftType.VAB, - ELCraftType.SPH, - }; + SelectFileCallback OnFileSelected; + CancelledCallback OnBrowseCancelled; public ELCraftType craftType { get; private set; } ELCraftTypeSelector typeSelector; + ELCraftSelector craftSelector; ELPartSelector partSelector; - ScrollView craftList; - ELCraftThumb craftThumb; - ScrollView craftInfo; - UIText craftDescription; UIButton loadButton; - UIButton generateThumb; - - ELCraftItem.List craftItems; - ToggleGroup craftGroup; - ELCraftItem _selectedCraft; - ELCraftItem selectedCraft - { - get { return _selectedCraft; } - set { - _selectedCraft = value; - UpdateCraftInfo (); - } - } -/* - public ELCraftType craftType - { - get { - return facilityType[(int) facility]; - } - }*/ public override void CreateUI () { base.CreateUI (); - UIScrollbar craftList_scrollbar; - UIScrollbar info_scrollbar; - this.Title (ELLocalization.SelectCraft) .Vertical () .ControlChildSize (true, true) @@ -104,53 +65,11 @@ public override void CreateUI () .OnSelectionChanged (CraftTypeSelected) .FlexibleLayout (true, true) .Finish () - .Add () - .Horizontal () - .ControlChildSize (true, true) - .ChildForceExpand (false,false) - - .Add (out partSelector) - .PreferredSize (321, -1) - .Finish () - .Add (out craftList) - .Horizontal (false) - .Vertical (true) - .Horizontal() - .ControlChildSize (true, true) - .ChildForceExpand (false, true) - .PreferredSize (321, -1) - .Add (out craftList_scrollbar, "Scrollbar") - .Direction(Scrollbar.Direction.BottomToTop) - .PreferredWidth (15) - .Finish () - .Finish () - .Add () - .Vertical () - .ControlChildSize (true, true) - .ChildForceExpand (false,false) - .Add (out craftThumb) - .Add (out generateThumb) - .Text ("Generate") - .OnClick (GenerateThumb) - .Anchor (AnchorPresets.StretchAll) - .SizeDelta (0, 0) - .Color (new UnityEngine.Color (0,0,0,0)) - .Finish () - .Finish () - .Add (out craftInfo) - .Horizontal (false) - .Vertical (true) - .Horizontal() - .ControlChildSize (true, true) - .ChildForceExpand (false, true) - .FlexibleLayout (true, false) - .PreferredSize (-1, 256) - .Add (out info_scrollbar, "Scrollbar") - .Direction(Scrollbar.Direction.BottomToTop) - .PreferredWidth (15) - .Finish () - .Finish () - .Finish () + .Add (out partSelector) + .OnSelectionChanged (OnSelectionChanged) + .Finish () + .Add (out craftSelector) + .OnSelectionChanged (OnSelectionChanged) .Finish () .Add () .Horizontal () @@ -162,7 +81,7 @@ public override void CreateUI () .Finish () .Add (out loadButton) .Text (ELLocalization.Load) - .OnClick (LoadCraft) + .OnClick (LoadSelection) .Finish () .Finish () .Add () @@ -172,172 +91,56 @@ public override void CreateUI () .FlexibleLayout (true, false) .Finish () .Finish (); - - craftList.VerticalScrollbar = craftList_scrollbar; - craftList.Viewport.FlexibleLayout (true, true); - craftList.Content - .Vertical () - .ControlChildSize (true, true) - .ChildForceExpand (false, false) - .Anchor (AnchorPresets.HorStretchTop) - .PreferredSizeFitter(true, false) - .SizeDelta (0, 0) - .ToggleGroup (out craftGroup) - .Finish (); - - craftInfo.VerticalScrollbar = info_scrollbar; - craftInfo.Viewport.FlexibleLayout (true, true); - craftInfo.Content - .Vertical () - .ControlChildSize (true, true) - .ChildForceExpand (false, false) - .Anchor (AnchorPresets.HorStretchTop) - .PreferredSizeFitter(true, false) - .SizeDelta (0, 0) - .Add (out craftDescription) - .Alignment (TextAlignmentOptions.TopLeft) - .FlexibleLayout (true, false) - .SizeDelta (0, 0) - .Finish () - .Finish (); - - - relativePath = ""; - craftThumb.Craft (""); - - craftItems = new ELCraftItem.List (craftGroup); - craftItems.Content = craftList.Content; - craftItems.onSelected = OnSelected; - } - - void GenerateThumb () - { - ELCraftThumb.Capture (selectedCraft.node, selectedCraft.type, - selectedCraft.fullPath); } void Cancel () { - OnBrowseCancelled (); SetActive (false); + OnBrowseCancelled (); } - void pipelineSucceed (ConfigNode node, ELCraftItem craft) - { - if (node != craft.node) { - craft.node.Save (craft.fullPath + ".original"); - node.Save (craft.fullPath); - } - OnFileSelected (selectedCraft.fullPath, selectedCraft.type); - } - - void pipelineFail (KSPUpgradePipeline.UpgradeFailOption opt, ConfigNode node, ELCraftItem craft) - { - if (opt == KSPUpgradePipeline.UpgradeFailOption.Cancel) { - OnBrowseCancelled (); - } else if (opt == KSPUpgradePipeline.UpgradeFailOption.LoadAnyway) { - pipelineSucceed (node, craft); - } - } - - void LoadCraft () + void LoadSelection () { SetActive (false); - KSPUpgradePipeline.Process (selectedCraft.node, selectedCraft.name, - SaveUpgradePipeline.LoadContext.Craft, - node => { pipelineSucceed (node, selectedCraft); }, - (opt, node) => { pipelineFail (opt, node, selectedCraft); }); - } - - string relativePath; - - void OnSelected (ELCraftItem craft) - { - if (selectedCraft == craft && Mouse.Left.GetDoubleClick (true)) { - LoadCraft (); + if (craftType == ELCraftType.Part) { + //partSelector } else { - selectedCraft = craft; + craftSelector.LoadCraft (); } } - void UpdateCraftInfo () + void OnSelectionChanged (bool canLoad, bool doLoad) { - if (selectedCraft != null) { - craftThumb.Craft (selectedCraft.thumbPath); - craftDescription.Text (selectedCraft.description); - loadButton.interactable = true; + if (canLoad && doLoad) { + LoadSelection (); } else { - craftDescription.Text (""); - craftThumb.Craft (""); - loadButton.interactable = false; + loadButton.interactable = canLoad; } } void CraftTypeSelected () { - SetRelativePath (typeSelector.craftType, typeSelector.stockCraft, ""); + var craftType = typeSelector.craftType; + var stockCraft = typeSelector.stockCraft; + craftSelector.SetCraftType (craftType, stockCraft); + partSelector.SetCraftType (craftType, stockCraft); } - void SetRelativePath (ELCraftType craftType, bool stock, string path) + void SetDelegates (SelectFileCallback onFileSelected, + CancelledCallback onCancel) { - SetActive (true); - this.craftType = craftType; - relativePath = path; - if (craftType == ELCraftType.Part) { - partSelector.SetVisible (true); - craftList.SetActive (false); - } else { - partSelector.SetVisible (false); - craftList.SetActive (true); - ScanDirectory (craftType, stock, path); - } + OnFileSelected = onFileSelected; + OnBrowseCancelled = onCancel; + craftSelector.SetDelegates (onFileSelected, onCancel); + partSelector.SetDelegates (onFileSelected, onCancel); } - bool ScanDirectory (ELCraftType type, bool stock, string path) + void SetCraftType (ELCraftType craftType, bool stock) { - string profile = HighLogic.SaveFolder; - string basePath = KSPUtil.ApplicationRootPath; - - craftItems.Clear (); - selectedCraft = null; - - if (!stock) { - basePath = basePath + $"saves/{profile}/"; - } - - switch (type) { - case ELCraftType.VAB: - case ELCraftType.SPH: - path = $"{basePath}Ships/{type.ToString ()}/{path}"; - break; - case ELCraftType.SubAss: - var subassPath = $"{basePath}Subassemblies/"; - if (!Directory.Exists (subassPath)) { - Directory.CreateDirectory (subassPath); - } - path = $"{subassPath}{path}"; - break; - } - - var directory = new DirectoryInfo (path); - var files = directory.GetFiles ("*.craft"); - - for (int i = 0; i < files.Length; i++) { - var fi = files[i]; - string fp = fi.FullName; - string mp = fi.FullName.Replace (fi.Extension, ".loadmeta"); - string tp; - if (stock) { - tp = ELCraftThumb.StockPath (type, fp); - } else { - tp = ELCraftThumb.UserPath (type, fp); - } - craftItems.Add (new ELCraftItem (fp, mp, tp, type)); - } - - UIKit.UpdateListContent (craftItems); - craftItems.Select (0); - return true; + SetActive (true); + typeSelector.SetCraftType (craftType, stock); + craftSelector.SetCraftType (craftType, stock); + partSelector.SetCraftType (craftType, stock); } protected override void Awake () @@ -365,9 +168,8 @@ public static void OpenDialog (ELCraftType craftType, string path, if (!craftBrowser) { craftBrowser = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELCraftBrowser"); } - craftBrowser.OnFileSelected = onFileSelected; - craftBrowser.OnBrowseCancelled = onCancel; - craftBrowser.SetRelativePath (craftType, false, path); + craftBrowser.SetDelegates (onFileSelected, onCancel); + craftBrowser.SetCraftType (craftType, false); } } } diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs new file mode 100644 index 00000000..ca1a3115 --- /dev/null +++ b/Source/UI/CraftSelector.cs @@ -0,0 +1,289 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + public class ELCraftSelector : Layout + { + public ELCraftType craftType { get; private set; } + + class CraftSelectionEvent : UnityEvent { } + CraftSelectionEvent onSelectionChanged; + + SelectFileCallback OnFileSelected; + CancelledCallback OnBrowseCancelled; + + ScrollView craftList; + ELCraftThumb craftThumb; + ScrollView craftInfo; + UIText craftDescription; + UIButton generateThumb; + + ELCraftItem.List craftItems; + ToggleGroup craftGroup; + ELCraftItem _selectedCraft; + ELCraftItem selectedCraft + { + get { return _selectedCraft; } + set { + _selectedCraft = value; + UpdateCraftInfo (); + } + } + + public override void CreateUI () + { + onSelectionChanged = new CraftSelectionEvent (); + + base.CreateUI (); + + UIScrollbar craftList_scrollbar; + UIScrollbar info_scrollbar; + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + + .Add (out craftList) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .PreferredSize (321, -1) + .Add (out craftList_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Add () + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add (out craftThumb) + .Add (out generateThumb) + .Text ("Generate") + .OnClick (GenerateThumb) + .Anchor (AnchorPresets.StretchAll) + .SizeDelta (0, 0) + .Color (new UnityEngine.Color (0,0,0,0)) + .Finish () + .Finish () + .Add (out craftInfo) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout (true, false) + .PreferredSize (-1, 256) + .Add (out info_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () + ; + + craftList.VerticalScrollbar = craftList_scrollbar; + craftList.Viewport.FlexibleLayout (true, true); + craftList.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .ToggleGroup (out craftGroup) + .Finish (); + + craftInfo.VerticalScrollbar = info_scrollbar; + craftInfo.Viewport.FlexibleLayout (true, true); + craftInfo.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .SizeDelta (0, 0) + .Add (out craftDescription) + .Alignment (TextAlignmentOptions.TopLeft) + .FlexibleLayout (true, false) + .SizeDelta (0, 0) + .Finish () + .Finish (); + + + relativePath = ""; + craftThumb.Craft (""); + + craftItems = new ELCraftItem.List (craftGroup); + craftItems.Content = craftList.Content; + craftItems.onSelected = OnSelected; + } + + public ELCraftSelector OnSelectionChanged (UnityAction action) + { + onSelectionChanged.AddListener (action); + return this; + } + + void GenerateThumb () + { + ELCraftThumb.Capture (selectedCraft.node, selectedCraft.type, + selectedCraft.fullPath); + } + + string relativePath; + + void pipelineSucceed (ConfigNode node, ELCraftItem craft) + { + if (node != craft.node) { + craft.node.Save (craft.fullPath + ".original"); + node.Save (craft.fullPath); + } + OnFileSelected (selectedCraft.fullPath, selectedCraft.type); + } + + void pipelineFail (KSPUpgradePipeline.UpgradeFailOption opt, ConfigNode node, ELCraftItem craft) + { + if (opt == KSPUpgradePipeline.UpgradeFailOption.Cancel) { + OnBrowseCancelled (); + } else if (opt == KSPUpgradePipeline.UpgradeFailOption.LoadAnyway) { + pipelineSucceed (node, craft); + } + } + + public void LoadCraft () + { + KSPUpgradePipeline.Process (selectedCraft.node, selectedCraft.name, + SaveUpgradePipeline.LoadContext.Craft, + node => { pipelineSucceed (node, selectedCraft); }, + (opt, node) => { pipelineFail (opt, node, selectedCraft); }); + } + + void OnSelected (ELCraftItem craft) + { + if (selectedCraft == craft && Mouse.Left.GetDoubleClick (true)) { + onSelectionChanged.Invoke (craft != null, true); + } else { + selectedCraft = craft; + //FIXME unloadable craft (missing parts) + onSelectionChanged.Invoke (craft != null, false); + } + } + + void UpdateCraftInfo () + { + if (selectedCraft != null) { + craftThumb.Craft (selectedCraft.thumbPath); + craftDescription.Text (selectedCraft.description); + } else { + craftDescription.Text (""); + craftThumb.Craft (""); + } + } + + public void SetDelegates (SelectFileCallback onFileSelected, + CancelledCallback onCancel) + { + OnFileSelected = onFileSelected; + OnBrowseCancelled = onCancel; + } + + public void SetCraftType (ELCraftType craftType, bool stock) + { + if (craftType != ELCraftType.Part) { + SetActive (true); + SetRelativePath (craftType, stock, ""); + } else { + SetActive (false); + } + } + + void SetRelativePath (ELCraftType craftType, bool stock, string path) + { + this.craftType = craftType; + relativePath = path; + ScanDirectory (craftType, stock, path); + } + + bool ScanDirectory (ELCraftType type, bool stock, string path) + { + string profile = HighLogic.SaveFolder; + string basePath = KSPUtil.ApplicationRootPath; + + craftItems.Clear (); + selectedCraft = null; + + if (!stock) { + basePath = basePath + $"saves/{profile}/"; + } + + switch (type) { + case ELCraftType.VAB: + case ELCraftType.SPH: + path = $"{basePath}Ships/{type.ToString ()}/{path}"; + break; + case ELCraftType.SubAss: + var subassPath = $"{basePath}Subassemblies/"; + if (!Directory.Exists (subassPath)) { + Directory.CreateDirectory (subassPath); + } + path = $"{subassPath}{path}"; + break; + } + + var directory = new DirectoryInfo (path); + var files = directory.GetFiles ("*.craft"); + + for (int i = 0; i < files.Length; i++) { + var fi = files[i]; + string fp = fi.FullName; + string mp = fi.FullName.Replace (fi.Extension, ".loadmeta"); + string tp; + if (stock) { + tp = ELCraftThumb.StockPath (type, fp); + } else { + tp = ELCraftThumb.UserPath (type, fp); + } + craftItems.Add (new ELCraftItem (fp, mp, tp, type)); + } + + UIKit.UpdateListContent (craftItems); + craftItems.Select (0); + return true; + } + } +} diff --git a/Source/UI/CraftTypeSelector.cs b/Source/UI/CraftTypeSelector.cs index 686ba822..f5bdfca1 100644 --- a/Source/UI/CraftTypeSelector.cs +++ b/Source/UI/CraftTypeSelector.cs @@ -106,16 +106,21 @@ public override void Style () { } - void SetType (ELCraftType type) + void UpdateControls () { - if (type == ELCraftType.VAB || type == ELCraftType.SPH) { + if (craftType == ELCraftType.VAB || craftType == ELCraftType.SPH) { stockToggle.interactable = true; stockToggle.SetIsOnWithoutNotify (stockCraft); } else { stockToggle.interactable = false; stockToggle.SetIsOnWithoutNotify (false); } + } + + void SetType (ELCraftType type) + { craftType = type; + UpdateControls (); onSelectionChanged.Invoke (); } @@ -130,6 +135,13 @@ public ELCraftTypeSelector OnSelectionChanged (UnityAction action) onSelectionChanged.AddListener (action); return this; } + + public void SetCraftType (ELCraftType craftType, bool stock) + { + this.craftType = craftType; + stockCraft = stock; + UpdateControls (); + } #region ILayoutElement Vector2 minSize; Vector2 preferredSize; diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 8218519a..5da867b9 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -373,6 +373,12 @@ void select (int index, bool on) } #endregion + class PartSelectionEvent : UnityEvent { } + PartSelectionEvent onSelectionChanged; + + SelectFileCallback OnFileSelected; + CancelledCallback OnBrowseCancelled; + ScrollView categoryView; ScrollView partListView; ELPartList partList; @@ -384,6 +390,8 @@ class CategoryDict : Dictionary { } public override void CreateUI () { + onSelectionChanged = new PartSelectionEvent (); + base.CreateUI (); UIScrollbar part_scrollbar; @@ -391,6 +399,7 @@ public override void CreateUI () this.Horizontal() .ControlChildSize (true, true) .ChildForceExpand (false, true) + .PreferredSize (247, 512) .Add (out categoryView) .Horizontal (false) .Vertical (true) @@ -451,6 +460,12 @@ public override void CreateUI () CreateLight (partListView.transform); } + public ELPartSelector OnSelectionChanged (UnityAction action) + { + onSelectionChanged.AddListener (action); + return this; + } + void CreateLight (Transform parent) { var lightObj = new GameObject ("ELPartList light"); @@ -518,10 +533,17 @@ void BuildCategories () } } - public void SetVisible (bool visible) + public void SetDelegates (SelectFileCallback onFileSelected, + CancelledCallback onCancel) + { + OnFileSelected = onFileSelected; + OnBrowseCancelled = onCancel; + } + + public void SetCraftType (ELCraftType craftType, bool stock) { - SetActive (visible); - if (visible) { + if (craftType == ELCraftType.Part) { + SetActive (true); if (partCategories == null) { BuildCategories (); } @@ -537,6 +559,7 @@ public void SetVisible (bool visible) Debug.Log ($"[ELPartSelector] SetVisible {categoryList.Count}"); UIKit.UpdateListContent (categoryList); } else { + SetActive (false); partList.Clear (); UIKit.UpdateListContent (partList); } From 91c1547938a0126149ae45d783de8802ee304334 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 09:48:02 +0900 Subject: [PATCH 084/150] Correct some part deprecation errors TechHidden is a crucial part of the equation. --- GameData/ExtraplanetaryLaunchpads/EL_MM.cfg | 2 +- .../Parts/ConstructionDrone/depr-part.cfg | 1 + GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg | 1 + GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg | 1 + Source/UI/PartSelector.cs | 6 ++++-- 5 files changed, 8 insertions(+), 3 deletions(-) diff --git a/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg b/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg index aba3126f..215db8a8 100644 --- a/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg +++ b/GameData/ExtraplanetaryLaunchpads/EL_MM.cfg @@ -85,7 +85,7 @@ @name = ELExtendingLaunchClamp // The part is not meant to be placed directly. Rather, EL will do a // switch when loading the craft file. - @TechHidden = true + TechHidden = true @category = none -tags = cck-el @MODULE[LaunchClamp] { diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg index 87e04f1f..7c9ebcd6 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/ConstructionDrone/depr-part.cfg @@ -21,6 +21,7 @@ PART TechRequired = Unresearchable tags = deprecated category = none + TechHidden = True entryCost = 12200 cost = 227400 title = #EL_ELConstructionDrone_title // Construction Drone diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg index e1a89ac0..dc6c3381 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/launchpad/part.cfg @@ -35,6 +35,7 @@ cost = 75000 TechRequired = Unresearchable tags = deprecated category = none +TechHidden = True title = #EL_ELLaunchpad_title // Launch Pad manufacturer = Kairyuu Shipping description = #EL_ELLaunchpad_desc // Build rockets off-planet! diff --git a/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg b/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg index 45eb9cb7..6b321890 100644 --- a/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg +++ b/GameData/ExtraplanetaryLaunchpads/Parts/runway/part.cfg @@ -32,6 +32,7 @@ tags = deprecated entryCost = 0 cost = 6000 category = none +TechHidden = True title = #EL_ELRunway_title // Runway manufacturer = Kairyuu Shipping description = #EL_ELRunway_desc // Build space planes off-planet! diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 5da867b9..07291b0c 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -115,7 +115,6 @@ public void Create (int index) .Add () .Group (group) .Category (this[index]) - .DebugLayout () .Finish () ; } @@ -516,7 +515,10 @@ void BuildCategories () var ap = PartLoader.LoadedPartsList[i]; var cat = ap.category; if (cat == PartCategories.none) { - if (ap.TechRequired == "Unresearcheable") { + if (ap.TechHidden || ap.TechRequired == "Unresearcheable") { + continue; + } + if (ap.name.StartsWith ("kerbalEVA") || ap.name == "flag") { continue; } } else if (cat == PartCategories.Propulsion) { From 8e674b21ca7f97918734913b9842493f0656e4e2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 10:04:03 +0900 Subject: [PATCH 085/150] Show selected part info including a larger view of the part. --- Source/Makefile | 1 + Source/UI/PartPreview.cs | 74 +++++++++++++++++++++++++++++++++++++++ Source/UI/PartSelector.cs | 74 ++++++++++++++++++++++++++++++++++----- 3 files changed, 140 insertions(+), 9 deletions(-) create mode 100644 Source/UI/PartPreview.cs diff --git a/Source/Makefile b/Source/Makefile index 0358c73b..8f546187 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -82,6 +82,7 @@ EL_FILES := \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ + UI/PartPreview.cs \ UI/PartSelector.cs \ UI/RenameDialog.cs \ UI/ResourceDisplay.cs \ diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs new file mode 100644 index 00000000..e97247ba --- /dev/null +++ b/Source/UI/PartPreview.cs @@ -0,0 +1,74 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; +using TMPro; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELPartPreview : UIObject + { + GameObject partIcon; + + public override void CreateUI () + { + this.Pivot (PivotPresets.MiddleCenter); + } + + public override void Style () + { + } + + protected override void OnDestroy () + { + base.OnDestroy (); + Destroy (partIcon); + } + + protected override void OnDisable () + { + base.OnDisable (); + Destroy (partIcon); + } + + public ELPartPreview AvailablePart (AvailablePart availablePart) + { + Destroy (partIcon); + + var rect = rectTransform.rect; + float size = Mathf.Min (rect.width, rect.height) / 2; + partIcon = GameObject.Instantiate (availablePart.iconPrefab); + partIcon.transform.SetParent (rectTransform, false); + partIcon.transform.localPosition = new Vector3 (0, 0, -size); + partIcon.transform.localScale = Vector3.one * size; + var rot = Quaternion.Euler (-15, 0, 0); + rot = rot * Quaternion.Euler (0, -30, 0); + partIcon.transform.rotation = rot; + partIcon.SetActive(true); + int layer = LayerMask.NameToLayer ("UIAdditional"); + EL_Utils.SetLayer (partIcon, layer, true); + return this; + } + } +} diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 07291b0c..b53f7998 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -333,6 +333,7 @@ class ELPartList : List, UIKit.IListObject { ToggleGroup group; + public UnityAction onSelected { get; set; } public Layout Content { get; set; } public RectTransform RectTransform { @@ -364,9 +365,7 @@ public ELPartList (ToggleGroup group) void select (int index, bool on) { if (on) { - var ap = this[index]; - Debug.Log ($"[ELPartList] select {index}i {ap.iconScale}"); - EL_Utils.dumpxform (ap.iconPrefab.transform, false); + onSelected.Invoke (this[index]); } } } @@ -380,9 +379,15 @@ class PartSelectionEvent : UnityEvent { } ScrollView categoryView; ScrollView partListView; + ELPartPreview partPreview; + ScrollView partInfoView; + UIText partInfo; + ELPartList partList; ELPartCategory.List categoryList; + AvailablePart selectedPart; + class APList : List { } class CategoryDict : Dictionary { } CategoryDict partCategories; @@ -394,11 +399,12 @@ public override void CreateUI () base.CreateUI (); UIScrollbar part_scrollbar; + UIScrollbar info_scrollbar; this.Horizontal() .ControlChildSize (true, true) - .ChildForceExpand (false, true) - .PreferredSize (247, 512) + .ChildForceExpand (false, false) + .PreferredSize (-1, 512) .Add (out categoryView) .Horizontal (false) .Vertical (true) @@ -413,11 +419,33 @@ public override void CreateUI () .ControlChildSize (true, true) .ChildForceExpand (false, true) .FlexibleLayout (true, true) + .PreferredSize (215, 512) .Add (out part_scrollbar, "Scrollbar") .Direction(Scrollbar.Direction.BottomToTop) .PreferredWidth (15) .Finish () .Finish () + .Add () + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .FlexibleLayout (true, true) + .Add (out partPreview) + .PreferredSize (256, 256) + .Finish () + .Add (out partInfoView) + .Horizontal (false) + .Vertical (true) + .Horizontal() + .ControlChildSize (true, true) + .ChildForceExpand (false, true) + .FlexibleLayout (true, true) + .Add (out info_scrollbar, "Scrollbar") + .Direction(Scrollbar.Direction.BottomToTop) + .PreferredWidth (15) + .Finish () + .Finish () + .Finish () ; ToggleGroup categoryGroup; @@ -456,7 +484,39 @@ public override void CreateUI () partList = new ELPartList (partGroup); partList.Content = partListView.Content; + partList.onSelected = OnSelected; CreateLight (partListView.transform); + + partInfoView.VerticalScrollbar = info_scrollbar; + partInfoView.Viewport.FlexibleLayout (true, true); + partInfoView.Content + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false, false) + .Anchor (AnchorPresets.HorStretchTop) + .PreferredSizeFitter(true, false) + .WidthDelta(0) + .Add (out partInfo) + .Alignment (TextAlignmentOptions.TopLeft) + .FlexibleLayout (true, true) + .Finish () + .Finish (); + } + + public override void Style () + { + } + + void OnSelected (AvailablePart availablePart) + { + if (availablePart != null) { + selectedPart = availablePart; + partPreview.AvailablePart (availablePart); + partInfo.Text (availablePart.title); + } else { + partPreview.AvailablePart (null); + partInfo.Text (""); + } } public ELPartSelector OnSelectionChanged (UnityAction action) @@ -488,10 +548,6 @@ void onPartListUpdate (Vector2 pos) } } - public override void Style () - { - } - void CategorySelected (PartCategories category) { var available = partCategories[category]; From 0ae51b22f35eb7495d056b855bedfc8be805e5bc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 11:50:03 +0900 Subject: [PATCH 086/150] Generate craft config for selected part The handling of the generated craft is wrong, but I've come up with a plan for handling this: the part selector becomes part of an in-flight part editor. --- Source/UI/CraftBrowser.cs | 4 ++-- Source/UI/PartSelector.cs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index f5ddce87..8179604f 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -103,7 +103,7 @@ void LoadSelection () { SetActive (false); if (craftType == ELCraftType.Part) { - //partSelector + partSelector.LoadPart (); } else { craftSelector.LoadCraft (); } @@ -120,7 +120,7 @@ void OnSelectionChanged (bool canLoad, bool doLoad) void CraftTypeSelected () { - var craftType = typeSelector.craftType; + craftType = typeSelector.craftType; var stockCraft = typeSelector.stockCraft; craftSelector.SetCraftType (craftType, stockCraft); partSelector.SetCraftType (craftType, stockCraft); diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index b53f7998..6f480f25 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -513,9 +513,11 @@ void OnSelected (AvailablePart availablePart) selectedPart = availablePart; partPreview.AvailablePart (availablePart); partInfo.Text (availablePart.title); + onSelectionChanged.Invoke (true, Mouse.Left.GetDoubleClick (true)); } else { partPreview.AvailablePart (null); partInfo.Text (""); + onSelectionChanged.Invoke (false, false); } } @@ -622,5 +624,41 @@ public void SetCraftType (ELCraftType craftType, bool stock) UIKit.UpdateListContent (partList); } } + + static ConfigNode CreateShip(AvailablePart availablePart) + { + var part = GameObject.Instantiate (availablePart.partPrefab) as Part; + ConfigNode node = new ConfigNode(); + + node.AddValue("ship", availablePart.title); + node.AddValue("version", Versioning.version_major + "." + Versioning.version_minor + "." + Versioning.Revision); + node.AddValue("description", "EL constructed part"); + node.AddValue("type", "VAB"); + node.AddValue("persistentId", 0); + node.AddValue("rot", Quaternion.identity); + node.AddValue("vesselType", part.vesselType); + + part.onBackup(); + ConfigNode partNode = node.AddNode("PART"); + + partNode.AddValue("part", part.partInfo.name + "_" + part.craftID); + partNode.AddValue("partName", part.partName); + partNode.AddValue("persistentId", part.persistentId); + partNode.AddValue("pos", Vector3.zero); + partNode.AddValue("attPos", Vector3.zero); + partNode.AddValue("attPos0", Vector3.zero); + partNode.AddValue("rot", Quaternion.identity); + partNode.AddValue("attRot", Quaternion.identity); + partNode.AddValue("attRot0", Quaternion.identity); + + return node; + } + + public void LoadPart () + { + ConfigNode node = CreateShip (selectedPart); + Debug.Log ($"[ELPartSelector] LoadPart {selectedPart.title}\n{node}"); + OnFileSelected (node.ToString (), ELCraftType.Part); + } } } From dfd15bb75c236ebcc626ac78252ddc80ed4201b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 15:34:44 +0900 Subject: [PATCH 087/150] Allow the part preview to be arbitrarily rotated --- Source/UI/PartPreview.cs | 70 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index e97247ba..9149270b 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -21,18 +21,28 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; +using UnityEngine.EventSystems; using TMPro; using KodeUI; namespace ExtraplanetaryLaunchpads { - public class ELPartPreview : UIObject + public class ELPartPreview : UIObject, + IBeginDragHandler, + IDragHandler, + IEndDragHandler { GameObject partIcon; + RectTransform canvasRect; public override void CreateUI () { + gameObject.AddComponent (); + + var canvas = GetComponentInParent (); + canvasRect = canvas.GetComponent (); + this.Pivot (PivotPresets.MiddleCenter); } @@ -70,5 +80,63 @@ public ELPartPreview AvailablePart (AvailablePart availablePart) EL_Utils.SetLayer (partIcon, layer, true); return this; } + +#region dragging + const float r = 1; + const float t = r * r / 2; + Vector3 TrackballVector (Vector2 xyVec) + { + float d = xyVec.x * xyVec.x + xyVec.y * xyVec.y; + Vector3 vec = xyVec; + + if (d < t) { + vec.z = -Mathf.Sqrt (r * r - d); + } else { + vec.z = -t / Mathf.Sqrt (d); + } + return vec; + } + + Quaternion DragRotation (PointerEventData eventData) + { + var rect = rectTransform.rect; + float invSize = 2 / Mathf.Min (rect.width, rect.height); + + Camera cam = eventData.pressEventCamera; + Vector2 delta = eventData.delta; + Vector2 endPos = eventData.position; + Vector2 startPos = endPos - delta; + + RectTransformUtility.ScreenPointToLocalPointInRectangle (canvasRect, endPos, cam, out endPos); + RectTransformUtility.ScreenPointToLocalPointInRectangle (canvasRect, startPos, cam, out startPos); + + endPos = endPos * invSize - Vector2.one; + startPos = startPos * invSize - Vector2.one; + + Vector3 end = TrackballVector (endPos); + Vector3 start = TrackballVector (startPos); + + Vector3 axis = Vector3.Cross (start, end); + + float angle = delta.magnitude * invSize * 60; + + return Quaternion.AngleAxis (angle, axis); + } + + public void OnBeginDrag (PointerEventData eventData) + { + } + + public void OnDrag (PointerEventData eventData) + { + Quaternion q = DragRotation (eventData); + Quaternion rot = partIcon.transform.rotation; + partIcon.transform.rotation = q * rot; + } + + public void OnEndDrag (PointerEventData eventData) + { + } +#endregion } } From 5d47b283830b4d22cd5ac456ef63b740e18d8c62 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 17:21:25 +0900 Subject: [PATCH 088/150] Create a craft file when a part is selected This is only the beginning for the part editor idea, but it's enough for testing how much can be cut from a craft file's PART node. --- Source/UI/PartSelector.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 6f480f25..157c256a 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -656,9 +656,23 @@ static ConfigNode CreateShip(AvailablePart availablePart) public void LoadPart () { + string basePath = KSPUtil.ApplicationRootPath; + string profile = HighLogic.SaveFolder; + string saveDir = "Parts/"; + string craft = "autopart.craft"; + string dir = $"{basePath}saves/{profile}/{saveDir}"; + + string fullPath = $"{dir}{craft}"; + ConfigNode node = CreateShip (selectedPart); - Debug.Log ($"[ELPartSelector] LoadPart {selectedPart.title}\n{node}"); - OnFileSelected (node.ToString (), ELCraftType.Part); + + Debug.Log ($"[ELPartSelector] LoadPart {selectedPart.title} {fullPath}\n{node}"); + if (!Directory.Exists (dir)) { + Directory.CreateDirectory (dir); + } + node.Save (fullPath); + + OnFileSelected (fullPath, ELCraftType.Part); } } } From 3a19d7a39a8795a3918d381c2bcc5455669f3873 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 15 Oct 2020 17:46:55 +0900 Subject: [PATCH 089/150] Check craft BoM dirty flag I forgot that was there. Fixes the non-updating craft info. --- Source/UI/BuildCraftView.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Source/UI/BuildCraftView.cs b/Source/UI/BuildCraftView.cs index 0036e702..794249c7 100644 --- a/Source/UI/BuildCraftView.cs +++ b/Source/UI/BuildCraftView.cs @@ -339,8 +339,13 @@ void UpdateCraftInfo () if (enable) { craftName.Text (control.craftName); StartCoroutine (WaitAndRebuildResources ()); - if (control.craftBoM != null || control.CreateBoM ()) { - craftBoM.Text(String.Join ("\n", control.craftBoM)); + if (control.craftBoM == null || control.craftBoMdirty) { + control.CreateBoM (); + } + if (control.craftBoM != null) { + craftBoM.Text (String.Join ("\n", control.craftBoM)); + } else { + craftBoM.Text (""); } craftThumb.Craft (control.craftType, control.filename); } From 8e3732e60303802a9ed91c76c92c0024cc9e38af Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 16 Oct 2020 13:08:18 +0900 Subject: [PATCH 090/150] Use correct rect for translating screen coords I'd copied the code from KodeUI's window dragger without really thinking (and it worked when centered). --- Source/UI/PartPreview.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index 9149270b..5019a49c 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -34,15 +34,11 @@ public class ELPartPreview : UIObject, IEndDragHandler { GameObject partIcon; - RectTransform canvasRect; public override void CreateUI () { gameObject.AddComponent (); - var canvas = GetComponentInParent (); - canvasRect = canvas.GetComponent (); - this.Pivot (PivotPresets.MiddleCenter); } @@ -107,11 +103,13 @@ Quaternion DragRotation (PointerEventData eventData) Vector2 endPos = eventData.position; Vector2 startPos = endPos - delta; - RectTransformUtility.ScreenPointToLocalPointInRectangle (canvasRect, endPos, cam, out endPos); - RectTransformUtility.ScreenPointToLocalPointInRectangle (canvasRect, startPos, cam, out startPos); + RectTransformUtility.ScreenPointToLocalPointInRectangle (rectTransform, endPos, cam, out endPos); + RectTransformUtility.ScreenPointToLocalPointInRectangle (rectTransform, startPos, cam, out startPos); - endPos = endPos * invSize - Vector2.one; - startPos = startPos * invSize - Vector2.one; + // The pivot is at the center of the rect, so the converted point's + // origin is at the center so no need to offset. + endPos = endPos * invSize; + startPos = startPos * invSize; Vector3 end = TrackballVector (endPos); Vector3 start = TrackballVector (startPos); @@ -120,6 +118,13 @@ Quaternion DragRotation (PointerEventData eventData) float angle = delta.magnitude * invSize * 60; + //Debug.Log ($"[ELPartPreview] DragRotation"); + //Debug.Log ($" s:({startPos.x}, {startPos.y})"); + //Debug.Log ($" e:({endPos.x}, {endPos.y})"); + //Debug.Log ($" s:({start.x}, {start.y}, {start.z})"); + //Debug.Log ($" e:({end.x}, {end.y}, {end.z})"); + //Debug.Log ($" a:({axis.x}, {axis.y}, {axis.z})"); + //Debug.Log ($" {angle}"); return Quaternion.AngleAxis (angle, axis); } @@ -132,6 +137,7 @@ public void OnDrag (PointerEventData eventData) Quaternion q = DragRotation (eventData); Quaternion rot = partIcon.transform.rotation; partIcon.transform.rotation = q * rot; + //Debug.Log ($" q:({q.x}, {q.y}, {q.z}, {q.w})"); } public void OnEndDrag (PointerEventData eventData) From a4ad37b34066561955f47ca986bdd63875a0c8f3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 13:34:55 +0900 Subject: [PATCH 091/150] Make a start on the part editor The basic layout is done (simpler than I expected) but with placeholders for the description and tweakables editors. The description editor needs multi-line text input (don't know if that will be a separate class or if I'll tweak UIInputField), and the tweakables editor will be a separate class when I get to it. --- Source/Makefile | 2 + Source/UI/CraftBrowser.cs | 15 +---- Source/UI/CraftSelector.cs | 45 +++++++++++-- Source/UI/Layout.cs | 44 +++++++++++++ Source/UI/Localization.cs | 6 ++ Source/UI/PartEditor.cs | 127 +++++++++++++++++++++++++++++++++++++ 6 files changed, 220 insertions(+), 19 deletions(-) create mode 100644 Source/UI/Layout.cs create mode 100644 Source/UI/PartEditor.cs diff --git a/Source/Makefile b/Source/Makefile index 8f546187..c29e3488 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -76,12 +76,14 @@ EL_FILES := \ UI/CraftTypeSelector.cs \ UI/BuildCraftView.cs \ UI/IResourceLine.cs \ + UI/Layout.cs \ UI/Localization.cs \ UI/MainWindow.cs \ UI/MiniToggle.cs \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ + UI/PartEditor.cs \ UI/PartPreview.cs \ UI/PartSelector.cs \ UI/RenameDialog.cs \ diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index 8179604f..c10bc57c 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -47,7 +47,6 @@ public class ELCraftBrowser : Window ELCraftTypeSelector typeSelector; ELCraftSelector craftSelector; - ELPartSelector partSelector; UIButton loadButton; public override void CreateUI () @@ -60,14 +59,11 @@ public override void CreateUI () .ChildForceExpand (false,false) .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) - .Pivot (PivotPresets.MiddleCenter) + .Pivot (PivotPresets.TopLeft) .Add (out typeSelector) .OnSelectionChanged (CraftTypeSelected) .FlexibleLayout (true, true) .Finish () - .Add (out partSelector) - .OnSelectionChanged (OnSelectionChanged) - .Finish () .Add (out craftSelector) .OnSelectionChanged (OnSelectionChanged) .Finish () @@ -102,11 +98,7 @@ void Cancel () void LoadSelection () { SetActive (false); - if (craftType == ELCraftType.Part) { - partSelector.LoadPart (); - } else { - craftSelector.LoadCraft (); - } + craftSelector.LoadCraft (); } void OnSelectionChanged (bool canLoad, bool doLoad) @@ -123,7 +115,6 @@ void CraftTypeSelected () craftType = typeSelector.craftType; var stockCraft = typeSelector.stockCraft; craftSelector.SetCraftType (craftType, stockCraft); - partSelector.SetCraftType (craftType, stockCraft); } void SetDelegates (SelectFileCallback onFileSelected, @@ -132,7 +123,6 @@ void SetDelegates (SelectFileCallback onFileSelected, OnFileSelected = onFileSelected; OnBrowseCancelled = onCancel; craftSelector.SetDelegates (onFileSelected, onCancel); - partSelector.SetDelegates (onFileSelected, onCancel); } void SetCraftType (ELCraftType craftType, bool stock) @@ -140,7 +130,6 @@ void SetCraftType (ELCraftType craftType, bool stock) SetActive (true); typeSelector.SetCraftType (craftType, stock); craftSelector.SetCraftType (craftType, stock); - partSelector.SetCraftType (craftType, stock); } protected override void Awake () diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index ca1a3115..8d515069 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -46,9 +46,13 @@ class CraftSelectionEvent : UnityEvent { } ScrollView craftList; ELCraftThumb craftThumb; + Layout partButtons; ScrollView craftInfo; UIText craftDescription; + UIButton generateThumb; + UIButton partNew; + UIButton partEdit; ELCraftItem.List craftItems; ToggleGroup craftGroup; @@ -100,6 +104,19 @@ public override void CreateUI () .Color (new UnityEngine.Color (0,0,0,0)) .Finish () .Finish () + .Add (out partButtons) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add (out partNew) + .Text (ELLocalization.New) + .OnClick (CreatePart) + .Finish () + .Add (out partEdit) + .Text (ELLocalization.Edit) + .OnClick (EditPart) + .Finish () + .Finish () .Add (out craftInfo) .Horizontal (false) .Vertical (true) @@ -165,6 +182,16 @@ void GenerateThumb () selectedCraft.fullPath); } + void CreatePart () + { + ELPartEditor.OpenEditor (null); + } + + void EditPart () + { + ELPartEditor.OpenEditor (selectedCraft); + } + string relativePath; void pipelineSucceed (ConfigNode node, ELCraftItem craft) @@ -209,9 +236,11 @@ void UpdateCraftInfo () if (selectedCraft != null) { craftThumb.Craft (selectedCraft.thumbPath); craftDescription.Text (selectedCraft.description); + partEdit.interactable = true; } else { craftDescription.Text (""); craftThumb.Craft (""); + partEdit.interactable = false; } } @@ -224,12 +253,9 @@ public void SetDelegates (SelectFileCallback onFileSelected, public void SetCraftType (ELCraftType craftType, bool stock) { - if (craftType != ELCraftType.Part) { - SetActive (true); - SetRelativePath (craftType, stock, ""); - } else { - SetActive (false); - } + SetActive (true); + SetRelativePath (craftType, stock, ""); + partButtons.SetActive (craftType == ELCraftType.Part); } void SetRelativePath (ELCraftType craftType, bool stock, string path) @@ -263,6 +289,13 @@ bool ScanDirectory (ELCraftType type, bool stock, string path) } path = $"{subassPath}{path}"; break; + case ELCraftType.Part: + var partsPath = $"{basePath}Parts/"; + if (!Directory.Exists (partsPath)) { + Directory.CreateDirectory (partsPath); + } + path = $"{partsPath}{path}"; + break; } var directory = new DirectoryInfo (path); diff --git a/Source/UI/Layout.cs b/Source/UI/Layout.cs new file mode 100644 index 00000000..fd5d8fcd --- /dev/null +++ b/Source/UI/Layout.cs @@ -0,0 +1,44 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class HorizontalLayout : Layout + { + public override void CreateUI () + { + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + ; + } + } + + public class VerticalLayout : Layout + { + public override void CreateUI () + { + this.Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + ; + } + } +} diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 0b65e88b..7301a798 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -65,5 +65,11 @@ public static class ELLocalization public static string SubAss { get; } = "Sub"; public static string Part { get; } = "Part"; // #autoLOC_6100048 public static string StockVessels { get; } = "Stock Vessels"; + public static string New { get; } = "New"; + public static string Edit { get; } = "Edit"; + public static string PartEditor { get; } = "Part Editor"; + public static string Save { get; } = "Save"; + public static string SaveAndClose { get; } = "Save and Close"; + public static string Close { get; } = "Close"; } } diff --git a/Source/UI/PartEditor.cs b/Source/UI/PartEditor.cs new file mode 100644 index 00000000..adb0d8d2 --- /dev/null +++ b/Source/UI/PartEditor.cs @@ -0,0 +1,127 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELPartEditor : Window + { + ELPartPreview partPreview; + VerticalLayout tweakables; + + public override void CreateUI () + { + base.CreateUI (); + + this.Title (ELLocalization.PartEditor) + .Vertical () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .PreferredSizeFitter (true, true) + .Anchor (AnchorPresets.MiddleCenter) + .Pivot (PivotPresets.MiddleCenter) + .Add () + .Add () + .Add () + .Add () + .Add () + .Text (ELLocalization.Save) + .OnClick (Save) + .FlexibleLayout (true, false) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add () + .Text (ELLocalization.SaveAndClose) + .OnClick (SaveAndClose) + .FlexibleLayout (true, false) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add () + .Text (ELLocalization.Close) + .OnClick (Close) + .FlexibleLayout (true, false) + .Finish () + .Finish () + .Add (out partPreview) + .PreferredSize (256, 256) + .Finish () + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Finish () + .Add (out tweakables) + .FlexibleLayout (true, true) + .PreferredSize (256, -1) + .Finish () + .Finish () + .Add () + .Text (ELVersionReport.GetVersion ()) + .Alignment (TextAlignmentOptions.Center) + .Size (12) + .FlexibleLayout (true, false) + .Finish () + .Finish (); + } + + void Save () + { + } + + void SaveAndClose () + { + Save (); + Close (); + } + + void Close () + { + SetActive (false); + } + + void EditPart (ELCraftItem editPart) + { + SetActive (true); + } + + static ELPartEditor partEditor; + public static void OpenEditor (ELCraftItem editPart) + { + if (!partEditor) { + partEditor = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELPartEditor"); + } + partEditor.EditPart (editPart); + } + } +} From 505631c8d328cc868181ca2d53b64197efd9f0ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 14:23:08 +0900 Subject: [PATCH 092/150] Set description editor to multi-line Turns out the support was already there (yay). Also, set input locks and find a KSP bug :P (despite input locks, double-tapping the space bar toggles int docking mode linear/rotation input control mode). --- Source/UI/PartEditor.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/UI/PartEditor.cs b/Source/UI/PartEditor.cs index adb0d8d2..00bbe6e2 100644 --- a/Source/UI/PartEditor.cs +++ b/Source/UI/PartEditor.cs @@ -78,7 +78,11 @@ public override void CreateUI () .Finish () .Finish () .Add () + .LineType (TMP_InputField.LineType.MultiLineNewline) + .OnFocusGained (SetControlLock) + .OnFocusLost (ClearControlLock) .FlexibleLayout (true, true) + .PreferredSize (-1, 128) .Finish () .Finish () .Add (out tweakables) @@ -95,6 +99,16 @@ public override void CreateUI () .Finish (); } + static void SetControlLock (string str = null) + { + InputLockManager.SetControlLock ("ELPartEditor_lock"); + } + + static void ClearControlLock (string str = null) + { + InputLockManager.RemoveControlLock ("ELPartEditor_lock"); + } + void Save () { } From 39387ac733138c0a98d5c92ca1b85390222f2222 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 14:58:36 +0900 Subject: [PATCH 093/150] Handle multi-line vessel descriptions This takes care of craft BoM description and the craft browser's description field. --- Source/BuildControl.cs | 3 ++- Source/UI/CraftItem.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/BuildControl.cs b/Source/BuildControl.cs index 060b401c..88170b1d 100644 --- a/Source/BuildControl.cs +++ b/Source/BuildControl.cs @@ -773,7 +773,8 @@ public bool CreateBoM () str = craftConfig.GetValue ("description"); if (!string.IsNullOrEmpty (str)) { - craftBoM.Add (Localizer.Format(str)); + str = Localizer.Format(str).Replace ('¨', '\n'); + craftBoM.Add (str); craftBoM.Add (""); // blank line } foreach (var part in craftConfig.GetNodes ("PART")) { diff --git a/Source/UI/CraftItem.cs b/Source/UI/CraftItem.cs index 9492aafc..9c1c0d59 100644 --- a/Source/UI/CraftItem.cs +++ b/Source/UI/CraftItem.cs @@ -62,6 +62,7 @@ public ELCraftItem (string craftPath, string metaPath, string thumbPath, ELCraft info.LoadDetailsFromCraftFile (node, craftPath); this.node = node; } + info.description = info.description.Replace ('¨', '\n'); this.thumbPath = thumbPath; type = craftType; } From 8c0b7a467136ee2a77bd2e2f8da8694306dcbda4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 15:38:03 +0900 Subject: [PATCH 094/150] Detect part preview size changes This fixes the incorrect scaling of the part icon when the previewer is initially created with a part to preview. --- Source/UI/PartPreview.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index 5019a49c..63bf48c4 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -58,10 +58,24 @@ protected override void OnDisable () Destroy (partIcon); } + protected override void OnRectTransformDimensionsChange () + { + if (partIcon) { + var rect = rectTransform.rect; + float size = Mathf.Min (rect.width, rect.height) / 2; + partIcon.transform.localPosition = new Vector3 (0, 0, -size); + partIcon.transform.localScale = Vector3.one * size; + } + } + public ELPartPreview AvailablePart (AvailablePart availablePart) { Destroy (partIcon); + if (availablePart == null) { + return this; + } + var rect = rectTransform.rect; float size = Mathf.Min (rect.width, rect.height) / 2; partIcon = GameObject.Instantiate (availablePart.iconPrefab); From 3590d6735806b5b35cce535d33638c8f29a0a6b0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 16:32:12 +0900 Subject: [PATCH 095/150] Move the part list light to a singleton This makes it easier to use over multiple part icon viewers. --- Source/Makefile | 1 + Source/UI/PartListLight.cs | 76 ++++++++++++++++++++++++++++++++++++++ Source/UI/PartPreview.cs | 9 +++++ Source/UI/PartSelector.cs | 23 +++++------- 4 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 Source/UI/PartListLight.cs diff --git a/Source/Makefile b/Source/Makefile index c29e3488..87c7d72f 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -84,6 +84,7 @@ EL_FILES := \ UI/PadSurveyView.cs \ UI/PadView.cs \ UI/PartEditor.cs \ + UI/PartListLight.cs \ UI/PartPreview.cs \ UI/PartSelector.cs \ UI/RenameDialog.cs \ diff --git a/Source/UI/PartListLight.cs b/Source/UI/PartListLight.cs new file mode 100644 index 00000000..cc3900e4 --- /dev/null +++ b/Source/UI/PartListLight.cs @@ -0,0 +1,76 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using UnityEngine; + +namespace ExtraplanetaryLaunchpads { + + public class ELPartListLight : MonoBehaviour + { + static ELPartListLight instance; + + void CreateLight () + { + var light = gameObject.AddComponent (); + light.type = LightType.Directional; + light.intensity = 0.5f; + light.colorTemperature = 6570; + light.cullingMask = 0x2000020; + } + + void Awake () + { + DontDestroyOnLoad (this); + CreateLight (); + users = 0; + } + + int users; + + void AddUser () + { + if (++users > 0) { + gameObject.SetActive (true); + } + } + + void RemoveUser () + { + if (--users < 1) { + gameObject.SetActive (false); + } + } + + public static void Enable () + { + if (!instance) { + var go = new GameObject ("ELPartList Light", + typeof (ELPartListLight)); + instance = go.GetComponent (); + } + instance.AddUser (); + } + + public static void Disable () + { + if (instance) { + instance.RemoveUser (); + } + } + } +} diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index 63bf48c4..e74d8efe 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -52,9 +52,18 @@ protected override void OnDestroy () Destroy (partIcon); } + protected override void OnEnable () + { + base.OnEnable (); + + ELPartListLight.Enable (); + } + protected override void OnDisable () { base.OnDisable (); + + ELPartListLight.Disable (); Destroy (partIcon); } diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 157c256a..5bc14535 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -485,7 +485,6 @@ public override void CreateUI () partList = new ELPartList (partGroup); partList.Content = partListView.Content; partList.onSelected = OnSelected; - CreateLight (partListView.transform); partInfoView.VerticalScrollbar = info_scrollbar; partInfoView.Viewport.FlexibleLayout (true, true); @@ -503,6 +502,16 @@ public override void CreateUI () .Finish (); } + protected override void OnEnable () + { + ELPartListLight.Enable (); + } + + protected override void OnDisable () + { + ELPartListLight.Disable (); + } + public override void Style () { } @@ -527,18 +536,6 @@ public ELPartSelector OnSelectionChanged (UnityAction action) return this; } - void CreateLight (Transform parent) - { - var lightObj = new GameObject ("ELPartList light"); - lightObj.transform.SetParent (parent, false); - - var light = lightObj.AddComponent (); - light.type = LightType.Directional; - light.intensity = 0.5f; - light.colorTemperature = 6570; - light.cullingMask = 0x2000020; - } - void onPartListUpdate (Vector2 pos) { TTC.SetupScreenSpaceMask (partListView.Viewport.rectTransform); From cb3aa233c84375555d51209c78876b65d4190555 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 17 Oct 2020 16:33:46 +0900 Subject: [PATCH 096/150] Add suggestion from fatcargo I suspect this is redundant with his feature request issue, but best to keep this interpretation safe anyway. --- TODO | 1 + 1 file changed, 1 insertion(+) diff --git a/TODO b/TODO index e8a9c216..91efdc01 100644 --- a/TODO +++ b/TODO @@ -3,6 +3,7 @@ refurbish Ablator Parachutes ... (resources with resource recipes) + Part upgrades (can upgrade to a craft file with a similar enough parts list) somehow mark parts as not being buildable requested by lgg From ac1334cdfdc348c3df865217b0205242513eacfe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 18 Oct 2020 22:35:31 +0900 Subject: [PATCH 097/150] Set part-craft description and preview --- Source/UI/PartEditor.cs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Source/UI/PartEditor.cs b/Source/UI/PartEditor.cs index 00bbe6e2..aa3af222 100644 --- a/Source/UI/PartEditor.cs +++ b/Source/UI/PartEditor.cs @@ -35,6 +35,9 @@ public class ELPartEditor : Window { ELPartPreview partPreview; VerticalLayout tweakables; + UIInputField descriptionInput; + + Part part; public override void CreateUI () { @@ -77,7 +80,7 @@ public override void CreateUI () .PreferredSize (256, 256) .Finish () .Finish () - .Add () + .Add (out descriptionInput) .LineType (TMP_InputField.LineType.MultiLineNewline) .OnFocusGained (SetControlLock) .OnFocusLost (ClearControlLock) @@ -127,6 +130,26 @@ void Close () void EditPart (ELCraftItem editPart) { SetActive (true); + descriptionInput.text = "EL constructed part"; + if (part) { + Destroy (part.gameObject); + } + part = null; + partPreview.AvailablePart (null); + if (editPart != null) { + var node = editPart.node; + if (node.HasValue ("description")) { + string description = node.GetValue ("description"); + descriptionInput.text = description.Replace ('¨', '\n'); + } + var partNode = node.GetNode ("PART"); + string partName = partNode.GetValue ("part").Split ('_')[0]; + + var partInfo = PartLoader.getPartInfoByName (partName); + if (partInfo != null) { + partPreview.AvailablePart (partInfo); + } + } } static ELPartEditor partEditor; From accc85240c563e93492b7b54da397f07e00d61f3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 19 Oct 2020 17:32:54 +0900 Subject: [PATCH 098/150] Deal with part variants for the part preview --- Source/UI/PartPreview.cs | 10 ++++++++++ Source/UI/PartSelector.cs | 26 +++++++++----------------- Source/lib/Utils.cs | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index e74d8efe..6f0c0bb1 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -34,6 +34,7 @@ public class ELPartPreview : UIObject, IEndDragHandler { GameObject partIcon; + Material []materials; public override void CreateUI () { @@ -97,6 +98,15 @@ public ELPartPreview AvailablePart (AvailablePart availablePart) partIcon.SetActive(true); int layer = LayerMask.NameToLayer ("UIAdditional"); EL_Utils.SetLayer (partIcon, layer, true); + + materials = EL_Utils.CollectMaterials (partIcon); + + if (availablePart.Variants != null + && availablePart.Variants.Count > 0) { + var variant = availablePart.partPrefab.baseVariant; + ModulePartVariants.ApplyVariant (null, partIcon.transform, + variant, materials, true); + } return this; } diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 5bc14535..f5dc7fbf 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -290,22 +290,6 @@ public ELPartItemView OnValueCanged (UnityAction action) return this; } - static Material []CollectMaterials (GameObject obj) - { - var materials = new List (); - var renderers = obj.GetComponentsInChildren (); - for (int i = renderers.Length; i-- > 0; ) { - var mats = renderers[i].materials; - for (int j = mats.Length; j-- > 0; ) { - if (!mats[j].HasProperty (PropertyIDs._MinX)) { - continue; - } - materials.Add (mats[j]); - } - } - return materials.ToArray (); - } - public ELPartItemView AvailablePart (AvailablePart availablePart) { if (partIcon) { @@ -322,7 +306,15 @@ public ELPartItemView AvailablePart (AvailablePart availablePart) partIcon.SetActive(true); int layer = LayerMask.NameToLayer ("UIAdditional"); EL_Utils.SetLayer (partIcon, layer, true); - materials = CollectMaterials (partIcon); + + materials = EL_Utils.CollectMaterials (partIcon); + + if (availablePart.Variants != null + && availablePart.Variants.Count > 0) { + var variant = availablePart.partPrefab.baseVariant; + ModulePartVariants.ApplyVariant (null, partIcon.transform, + variant, materials, true); + } return this; } } diff --git a/Source/lib/Utils.cs b/Source/lib/Utils.cs index 573528b6..c6c6eaa2 100644 --- a/Source/lib/Utils.cs +++ b/Source/lib/Utils.cs @@ -248,5 +248,21 @@ public static void SetLayer (GameObject obj, int layer, bool recursive) } } } + + public static Material []CollectMaterials (GameObject obj) + { + var materials = new List (); + var renderers = obj.GetComponentsInChildren (); + for (int i = renderers.Length; i-- > 0; ) { + var mats = renderers[i].materials; + for (int j = mats.Length; j-- > 0; ) { + if (!mats[j].HasProperty (PropertyIDs._MinX)) { + continue; + } + materials.Add (mats[j]); + } + } + return materials.ToArray (); + } } } From 2ae3e0e8b25b4300646225f998c5343c075fa249 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 19 Oct 2020 17:43:43 +0900 Subject: [PATCH 099/150] Rename the part editor window --- Source/Makefile | 2 +- Source/UI/CraftSelector.cs | 4 ++-- Source/UI/{PartEditor.cs => PartEditorWindow.cs} | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) rename Source/UI/{PartEditor.cs => PartEditorWindow.cs} (93%) diff --git a/Source/Makefile b/Source/Makefile index 87c7d72f..9eabead6 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -83,7 +83,7 @@ EL_FILES := \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ - UI/PartEditor.cs \ + UI/PartEditorWindow.cs \ UI/PartListLight.cs \ UI/PartPreview.cs \ UI/PartSelector.cs \ diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index 8d515069..08cd5a23 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -184,12 +184,12 @@ void GenerateThumb () void CreatePart () { - ELPartEditor.OpenEditor (null); + ELPartEditorWindow.OpenEditor (null); } void EditPart () { - ELPartEditor.OpenEditor (selectedCraft); + ELPartEditorWindow.OpenEditor (selectedCraft); } string relativePath; diff --git a/Source/UI/PartEditor.cs b/Source/UI/PartEditorWindow.cs similarity index 93% rename from Source/UI/PartEditor.cs rename to Source/UI/PartEditorWindow.cs index aa3af222..2f48cb8d 100644 --- a/Source/UI/PartEditor.cs +++ b/Source/UI/PartEditorWindow.cs @@ -31,7 +31,7 @@ You should have received a copy of the GNU General Public License namespace ExtraplanetaryLaunchpads { - public class ELPartEditor : Window + public class ELPartEditorWindow : Window { ELPartPreview partPreview; VerticalLayout tweakables; @@ -152,13 +152,13 @@ void EditPart (ELCraftItem editPart) } } - static ELPartEditor partEditor; + static ELPartEditorWindow partEditorWindow; public static void OpenEditor (ELCraftItem editPart) { - if (!partEditor) { - partEditor = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELPartEditor"); + if (!partEditorWindow) { + partEditorWindow = UIKit.CreateUI (ELWindowManager.appCanvasRect, "ELPartEditorWindow"); } - partEditor.EditPart (editPart); + partEditorWindow.EditPart (editPart); } } } From 31aad8c946921759154442b2d858cc5d9585a099 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 21 Oct 2020 12:27:09 +0900 Subject: [PATCH 100/150] Implement switching between part select and edit Also handles cancel and does a lot of setup for part editing. --- Source/Makefile | 1 + Source/UI/Localization.cs | 2 + Source/UI/PartEditorView.cs | 183 ++++++++++++++++++++++++++++++++++ Source/UI/PartEditorWindow.cs | 110 ++++++-------------- Source/UI/PartPreview.cs | 56 +++++++++-- Source/UI/PartSelector.cs | 130 ++++++++++++++---------- 6 files changed, 336 insertions(+), 146 deletions(-) create mode 100644 Source/UI/PartEditorView.cs diff --git a/Source/Makefile b/Source/Makefile index 9eabead6..0a17189d 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -83,6 +83,7 @@ EL_FILES := \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ + UI/PartEditorView.cs \ UI/PartEditorWindow.cs \ UI/PartListLight.cs \ UI/PartPreview.cs \ diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 7301a798..81238cc1 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -23,8 +23,10 @@ public static class ELLocalization public static string BuildManager { get; } = "Build Manager"; public static string ResourceManager { get; } = "Resource Manager"; public static string Productivity { get; } = "Productivity:"; + public static string Select { get; } = "Select"; public static string SelectCraft { get; } = "Select Craft"; public static string SelectedCraft { get; } = "Selected Craft"; + public static string SelectPart { get; } = "Select Part"; public static string Reload { get; } = "Reload"; public static string Clear { get; } = "Clear"; public static string Pad { get; } = "pad"; diff --git a/Source/UI/PartEditorView.cs b/Source/UI/PartEditorView.cs new file mode 100644 index 00000000..d236096c --- /dev/null +++ b/Source/UI/PartEditorView.cs @@ -0,0 +1,183 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +namespace ExtraplanetaryLaunchpads { + + public class ELPartEditorView : Layout + { + ELPartPreview partPreview; + VerticalLayout tweakables; + UIInputField descriptionInput; + + Part part; + + SelectPartCallback OnSelectPart; + CancelledCallback OnEditorClose; + + public override void CreateUI () + { + base.CreateUI (); + + this.Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add () + .Add () + .Add () + .Add () + .Text (ELLocalization.SelectPart) + .OnClick (SelectPart) + .FlexibleLayout (true, false) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add () + .Text (ELLocalization.Save) + .OnClick (Save) + .FlexibleLayout (true, false) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add () + .Text (ELLocalization.SaveAndClose) + .OnClick (SaveAndClose) + .FlexibleLayout (true, false) + .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add () + .Text (ELLocalization.Close) + .OnClick (Close) + .FlexibleLayout (true, false) + .Finish () + .Finish () + .Add (out partPreview) + .PreferredSize (256, 256) + .Finish () + .Finish () + .Add (out descriptionInput) + .LineType (TMP_InputField.LineType.MultiLineNewline) + .OnFocusGained (SetControlLock) + .OnFocusLost (ClearControlLock) + .FlexibleLayout (true, true) + .PreferredSize (-1, 128) + .Finish () + .Finish () + .Add (out tweakables) + .FlexibleLayout (true, true) + .PreferredSize (256, -1) + .Finish () + ; + } + + static void SetControlLock (string str = null) + { + InputLockManager.SetControlLock ("ELPartEditor_lock"); + } + + static void ClearControlLock (string str = null) + { + InputLockManager.RemoveControlLock ("ELPartEditor_lock"); + } + + void SelectPart () + { + OnSelectPart (part.partInfo); + } + + void Save () + { + } + + void SaveAndClose () + { + Save (); + Close (); + } + + void Close () + { + Destroy (part); + part = null; + OnEditorClose (); + } + + public ELPartEditorView SetDelegates (SelectPartCallback onSelectPart, + CancelledCallback onEditorClose) + { + OnSelectPart = onSelectPart; + OnEditorClose = onEditorClose; + return this; + } + + public void EditPart (AvailablePart availablePart) + { + SetActive (true); + if (availablePart != null) { + part = (Part)GameObject.Instantiate (availablePart.partPrefab); + part.enabled = false; + EL_Utils.DisableModules (part.gameObject); + EL_Utils.RemoveColliders (part.gameObject); + part.gameObject.SetActive (true); + partPreview.Part (part); + } else { + if (!part) { + Close (); + } + } + } + + public void EditPart (ELCraftItem editPart) + { + descriptionInput.text = "EL constructed part"; + if (part) { + Destroy (part.gameObject); + } + part = null; + partPreview.AvailablePart (null); + if (editPart != null) { + var node = editPart.node; + if (node.HasValue ("description")) { + string description = node.GetValue ("description"); + descriptionInput.text = description.Replace ('¨', '\n'); + } + var partNode = node.GetNode ("PART"); + string partName = partNode.GetValue ("part").Split ('_')[0]; + + var partInfo = PartLoader.getPartInfoByName (partName); + EditPart (partInfo); + } + } + } +} diff --git a/Source/UI/PartEditorWindow.cs b/Source/UI/PartEditorWindow.cs index 2f48cb8d..50c44690 100644 --- a/Source/UI/PartEditorWindow.cs +++ b/Source/UI/PartEditorWindow.cs @@ -33,11 +33,8 @@ namespace ExtraplanetaryLaunchpads { public class ELPartEditorWindow : Window { - ELPartPreview partPreview; - VerticalLayout tweakables; - UIInputField descriptionInput; - - Part part; + ELPartEditorView partEditor; + ELPartSelector partSelector; public override void CreateUI () { @@ -50,48 +47,11 @@ public override void CreateUI () .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) .Pivot (PivotPresets.MiddleCenter) - .Add () - .Add () - .Add () - .Add () - .Add () - .Text (ELLocalization.Save) - .OnClick (Save) - .FlexibleLayout (true, false) - .Finish () - .Add () - .FlexibleLayout (true, true) - .Finish () - .Add () - .Text (ELLocalization.SaveAndClose) - .OnClick (SaveAndClose) - .FlexibleLayout (true, false) - .Finish () - .Add () - .FlexibleLayout (true, true) - .Finish () - .Add () - .Text (ELLocalization.Close) - .OnClick (Close) - .FlexibleLayout (true, false) - .Finish () - .Finish () - .Add (out partPreview) - .PreferredSize (256, 256) - .Finish () - .Finish () - .Add (out descriptionInput) - .LineType (TMP_InputField.LineType.MultiLineNewline) - .OnFocusGained (SetControlLock) - .OnFocusLost (ClearControlLock) - .FlexibleLayout (true, true) - .PreferredSize (-1, 128) - .Finish () - .Finish () - .Add (out tweakables) - .FlexibleLayout (true, true) - .PreferredSize (256, -1) - .Finish () + .Add (out partEditor) + .SetDelegates (onSelectPart, onEditorClose) + .Finish () + .Add (out partSelector) + .SetDelegates (onPartSelected, onPartSelectCancelled) .Finish () .Add () .Text (ELVersionReport.GetVersion ()) @@ -102,54 +62,40 @@ public override void CreateUI () .Finish (); } - static void SetControlLock (string str = null) - { - InputLockManager.SetControlLock ("ELPartEditor_lock"); - } - - static void ClearControlLock (string str = null) + void onSelectPart (AvailablePart availablePart) { - InputLockManager.RemoveControlLock ("ELPartEditor_lock"); + partSelector.SetVisible (true); + partEditor.SetActive (false); + partSelector.SetSelectedPart (availablePart); } - void Save () + void onEditorClose () { + SetActive (false); } - void SaveAndClose () + void EditPart (ELCraftItem editPart) { - Save (); - Close (); + SetActive (true); + if (editPart == null) { + partSelector.SetVisible (true); + partEditor.SetActive (false); + } else { + partSelector.SetVisible (false); + partEditor.EditPart (editPart); + } } - void Close () + void onPartSelected (AvailablePart availablePart) { - SetActive (false); + partSelector.SetVisible (false); + partEditor.EditPart (availablePart); } - void EditPart (ELCraftItem editPart) + void onPartSelectCancelled () { - SetActive (true); - descriptionInput.text = "EL constructed part"; - if (part) { - Destroy (part.gameObject); - } - part = null; - partPreview.AvailablePart (null); - if (editPart != null) { - var node = editPart.node; - if (node.HasValue ("description")) { - string description = node.GetValue ("description"); - descriptionInput.text = description.Replace ('¨', '\n'); - } - var partNode = node.GetNode ("PART"); - string partName = partNode.GetValue ("part").Split ('_')[0]; - - var partInfo = PartLoader.getPartInfoByName (partName); - if (partInfo != null) { - partPreview.AvailablePart (partInfo); - } - } + partSelector.SetVisible (false); + partEditor.EditPart ((AvailablePart) null); } static ELPartEditorWindow partEditorWindow; diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index 6f0c0bb1..f4756aba 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -33,6 +33,7 @@ public class ELPartPreview : UIObject, IDragHandler, IEndDragHandler { + bool noDestroy; GameObject partIcon; Material []materials; @@ -56,7 +57,7 @@ protected override void OnDestroy () protected override void OnEnable () { base.OnEnable (); - + Debug.Log ($"[ELPartPreview] OnEnable {noDestroy}"); ELPartListLight.Enable (); } @@ -64,8 +65,11 @@ protected override void OnDisable () { base.OnDisable (); + Debug.Log ($"[ELPartPreview] OnDisable {noDestroy}"); ELPartListLight.Disable (); - Destroy (partIcon); + if (!noDestroy) { + Destroy (partIcon); + } } protected override void OnRectTransformDimensionsChange () @@ -78,17 +82,13 @@ protected override void OnRectTransformDimensionsChange () } } - public ELPartPreview AvailablePart (AvailablePart availablePart) + void PartIcon (GameObject partIcon) { - Destroy (partIcon); - - if (availablePart == null) { - return this; - } + this.partIcon = partIcon; var rect = rectTransform.rect; float size = Mathf.Min (rect.width, rect.height) / 2; - partIcon = GameObject.Instantiate (availablePart.iconPrefab); + partIcon.transform.SetParent (rectTransform, false); partIcon.transform.localPosition = new Vector3 (0, 0, -size); partIcon.transform.localScale = Vector3.one * size; @@ -100,6 +100,19 @@ public ELPartPreview AvailablePart (AvailablePart availablePart) EL_Utils.SetLayer (partIcon, layer, true); materials = EL_Utils.CollectMaterials (partIcon); + } + + public ELPartPreview AvailablePart (AvailablePart availablePart) + { + Destroy (partIcon); + + if (availablePart == null) { + return this; + } + + noDestroy = false; + + PartIcon (GameObject.Instantiate (availablePart.iconPrefab)); if (availablePart.Variants != null && availablePart.Variants.Count > 0) { @@ -110,6 +123,28 @@ public ELPartPreview AvailablePart (AvailablePart availablePart) return this; } + public ELPartPreview Part (Part part) + { + Destroy (partIcon); + + if (part == null) { + return this; + } + + noDestroy = true; + + // the icon prefab is a wrapper of the part model, and the part + // model is the only child + var pi = part.partInfo.iconPrefab.transform.GetChild (0); + var go = new GameObject(); + part.transform.SetParent (go.transform, false); + part.transform.localScale = pi.localScale; + part.transform.localPosition = pi.localPosition; + + PartIcon (go); + return this; + } + #region dragging const float r = 1; const float t = r * r / 2; @@ -167,6 +202,9 @@ public void OnBeginDrag (PointerEventData eventData) public void OnDrag (PointerEventData eventData) { + if (!partIcon) { + return; + } Quaternion q = DragRotation (eventData); Quaternion rot = partIcon.transform.rotation; partIcon.transform.rotation = q * rot; diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index f5dc7fbf..93c5b620 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -36,6 +36,8 @@ namespace ExtraplanetaryLaunchpads { using TTC = KSP.UI.Screens.Editor.PartListTooltipController; + public delegate void SelectPartCallback (AvailablePart availablePart); + public class ELPartSelector : Layout { static PartCategories []categoryOrder = { @@ -130,13 +132,16 @@ public List (ToggleGroup group) this.group = group; } - public void Select (int index) + public void Select (PartCategories category) { - if (index >= 0 && index < Count) { - group.SetAllTogglesOff (false); - var child = Content.rectTransform.GetChild (index); + group.SetAllTogglesOff (false); + for (int i = Content.rectTransform.childCount; i-- > 0; ) { + var child = Content.rectTransform.GetChild (i); var view = child.GetComponent (); - view.Select (); + if (view.category.category == category) { + view.SelectCategory (); + break; + } } } } @@ -151,7 +156,7 @@ class ELPartCategoryView : UIObject, ILayoutElement Image image; UIImage icon; - ELPartCategory category; + public ELPartCategory category { get; private set; } public override void CreateUI () { @@ -193,6 +198,11 @@ public void Select () category.Select (); } + public void SelectCategory () + { + toggle.isOn = true; + } + public ELPartCategoryView Group (ToggleGroup group) { toggle.group = group; @@ -363,11 +373,8 @@ void select (int index, bool on) } #endregion - class PartSelectionEvent : UnityEvent { } - PartSelectionEvent onSelectionChanged; - - SelectFileCallback OnFileSelected; - CancelledCallback OnBrowseCancelled; + SelectPartCallback OnPartSelected; + CancelledCallback OnPartCancelled; ScrollView categoryView; ScrollView partListView; @@ -386,8 +393,6 @@ class CategoryDict : Dictionary { } public override void CreateUI () { - onSelectionChanged = new PartSelectionEvent (); - base.CreateUI (); UIScrollbar part_scrollbar; @@ -437,6 +442,16 @@ public override void CreateUI () .PreferredWidth (15) .Finish () .Finish () + .Add () + .Add () + .Text (ELLocalization.Select) + .OnClick (SelectPart) + .Finish () + .Add () + .Text (ELLocalization.Cancel) + .OnClick (CancelPart) + .Finish () + .Finish () .Finish () ; @@ -508,24 +523,35 @@ public override void Style () { } + void UpdateSelectedPart (AvailablePart availablePart) + { + selectedPart = availablePart; + partPreview.AvailablePart (availablePart); + partInfo.Text (availablePart.title); + } + void OnSelected (AvailablePart availablePart) { if (availablePart != null) { - selectedPart = availablePart; - partPreview.AvailablePart (availablePart); - partInfo.Text (availablePart.title); - onSelectionChanged.Invoke (true, Mouse.Left.GetDoubleClick (true)); + bool selected = Mouse.Left.GetDoubleClick (true); + UpdateSelectedPart (availablePart); + if (selected) { + OnPartSelected (selectedPart); + } } else { partPreview.AvailablePart (null); partInfo.Text (""); - onSelectionChanged.Invoke (false, false); } } - public ELPartSelector OnSelectionChanged (UnityAction action) + void SelectPart () { - onSelectionChanged.AddListener (action); - return this; + OnPartSelected (selectedPart); + } + + void CancelPart () + { + OnPartCancelled (); } void onPartListUpdate (Vector2 pos) @@ -552,6 +578,19 @@ void CategorySelected (PartCategories category) UIKit.UpdateListContent (partList); } + PartCategories GetCategory (AvailablePart ap) + { + var cat = ap.category; + if (cat == PartCategories.Propulsion) { + if (ap.moduleInfos.Exists (p => p.moduleName == "Engine")) { + cat = PartCategories.Engine; + } else { + cat = PartCategories.FuelTank; + } + } + return cat; + } + void BuildCategories () { partCategories = new CategoryDict (); @@ -560,7 +599,7 @@ void BuildCategories () } for (int i = PartLoader.LoadedPartsList.Count; i-- > 0; ) { var ap = PartLoader.LoadedPartsList[i]; - var cat = ap.category; + var cat = GetCategory (ap); if (cat == PartCategories.none) { if (ap.TechHidden || ap.TechRequired == "Unresearcheable") { continue; @@ -568,12 +607,6 @@ void BuildCategories () if (ap.name.StartsWith ("kerbalEVA") || ap.name == "flag") { continue; } - } else if (cat == PartCategories.Propulsion) { - if (ap.moduleInfos.Exists (p => p.moduleName == "Engine")) { - cat = PartCategories.Engine; - } else { - cat = PartCategories.FuelTank; - } } partCategories[cat].Add (ap); } @@ -582,16 +615,17 @@ void BuildCategories () } } - public void SetDelegates (SelectFileCallback onFileSelected, - CancelledCallback onCancel) + public ELPartSelector SetDelegates (SelectPartCallback onPartSelected, + CancelledCallback onPartCancel) { - OnFileSelected = onFileSelected; - OnBrowseCancelled = onCancel; + OnPartSelected = onPartSelected; + OnPartCancelled = onPartCancel; + return this; } - public void SetCraftType (ELCraftType craftType, bool stock) + public void SetVisible (bool visible) { - if (craftType == ELCraftType.Part) { + if (visible) { SetActive (true); if (partCategories == null) { BuildCategories (); @@ -614,6 +648,13 @@ public void SetCraftType (ELCraftType craftType, bool stock) } } + public void SetSelectedPart (AvailablePart availablePart) + { + var cat = GetCategory (availablePart); + categoryList.Select (cat); + UpdateSelectedPart (availablePart); + } + static ConfigNode CreateShip(AvailablePart availablePart) { var part = GameObject.Instantiate (availablePart.partPrefab) as Part; @@ -642,26 +683,5 @@ static ConfigNode CreateShip(AvailablePart availablePart) return node; } - - public void LoadPart () - { - string basePath = KSPUtil.ApplicationRootPath; - string profile = HighLogic.SaveFolder; - string saveDir = "Parts/"; - string craft = "autopart.craft"; - string dir = $"{basePath}saves/{profile}/{saveDir}"; - - string fullPath = $"{dir}{craft}"; - - ConfigNode node = CreateShip (selectedPart); - - Debug.Log ($"[ELPartSelector] LoadPart {selectedPart.title} {fullPath}\n{node}"); - if (!Directory.Exists (dir)) { - Directory.CreateDirectory (dir); - } - node.Save (fullPath); - - OnFileSelected (fullPath, ELCraftType.Part); - } } } From 1ceb279a61581cd22ae5551a68f8c82a1bf105f9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 21 Oct 2020 12:39:01 +0900 Subject: [PATCH 101/150] Clean up the mess of nested classes Proved to be more trouble than it was worth --- Source/Makefile | 4 + Source/UI/PartCategory.cs | 123 +++++++++++++ Source/UI/PartCategoryView.cs | 135 +++++++++++++++ Source/UI/PartItemView.cs | 114 +++++++++++++ Source/UI/PartList.cs | 77 +++++++++ Source/UI/PartSelector.cs | 313 ---------------------------------- 6 files changed, 453 insertions(+), 313 deletions(-) create mode 100644 Source/UI/PartCategory.cs create mode 100644 Source/UI/PartCategoryView.cs create mode 100644 Source/UI/PartItemView.cs create mode 100644 Source/UI/PartList.cs diff --git a/Source/Makefile b/Source/Makefile index 0a17189d..49bdd93a 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -83,8 +83,12 @@ EL_FILES := \ UI/PadLaunchpadView.cs \ UI/PadSurveyView.cs \ UI/PadView.cs \ + UI/PartCategory.cs \ + UI/PartCategoryView.cs \ UI/PartEditorView.cs \ UI/PartEditorWindow.cs \ + UI/PartItemView.cs \ + UI/PartList.cs \ UI/PartListLight.cs \ UI/PartPreview.cs \ UI/PartSelector.cs \ diff --git a/Source/UI/PartCategory.cs b/Source/UI/PartCategory.cs new file mode 100644 index 00000000..d88fa10a --- /dev/null +++ b/Source/UI/PartCategory.cs @@ -0,0 +1,123 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + class ELPartCategory + { + public delegate void CategorySelectedCallback (PartCategories category); + public CategorySelectedCallback CategorySelected; + public Sprite onIcon { get; private set; } + public Sprite offIcon { get; private set; } + public PartCategories category { get; private set; } + + static Sprite []elFilterSprites = new Sprite[2]; + static string []elFilterNames = { + "icon_filter_n", + "icon_filter_s" + }; + + static Sprite FindSprite (PartCategories category, bool on) + { + int ind = on ? 1 : 0; + if (elFilterSprites[ind] == null) { + string path = $"GameData/ExtraplanetaryLaunchpads/Textures/{elFilterNames[ind]}.png"; + var tex = new Texture2D (32, 32, TextureFormat.ARGB32, false); + bool ok = EL_Utils.LoadImage (ref tex, path); + elFilterSprites[ind] = EL_Utils.MakeSprite (tex); + Debug.Log ($"[ELPartCategory] FindSprite {category} {path} {ok}"); + } + return elFilterSprites[ind]; + } + + public ELPartCategory (PartCategories category) + { + Debug.Log ($"[ELPartCategory] {category}"); + this.category = category; + onIcon = FindSprite (category, true); + offIcon = FindSprite (category, false); + } + + public void Select () + { + CategorySelected (category); + } + +#region ELPartCategory.List + public class List : List, UIKit.IListObject + { + ToggleGroup group; + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Group (group) + .Category (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var view = obj.GetComponent (); + view.Category (this[index]); + } + + public List (ToggleGroup group) + { + this.group = group; + } + + public void Select (PartCategories category) + { + group.SetAllTogglesOff (false); + for (int i = Content.rectTransform.childCount; i-- > 0; ) { + var child = Content.rectTransform.GetChild (i); + var view = child.GetComponent (); + if (view.category.category == category) { + view.SelectCategory (); + break; + } + } + } + } +#endregion + } +} diff --git a/Source/UI/PartCategoryView.cs b/Source/UI/PartCategoryView.cs new file mode 100644 index 00000000..ecaa4b27 --- /dev/null +++ b/Source/UI/PartCategoryView.cs @@ -0,0 +1,135 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + class ELPartCategoryView : UIObject, ILayoutElement + { + Toggle toggle; + Image image; + UIImage icon; + + public ELPartCategory category { get; private set; } + + public override void CreateUI () + { + image = gameObject.AddComponent (); + image.type = UnityEngine.UI.Image.Type.Sliced; + + this.PreferredSize (32, 32) + .Add (out icon) + .Anchor (AnchorPresets.StretchAll) + .Pivot (PivotPresets.MiddleCenter) + .SizeDelta(0, 0) + .Finish () + ; + + toggle = gameObject.AddComponent (); + toggle.onValueChanged.AddListener (onValueChanged); + toggle.targetGraphic = image; + toggle.graphic = icon.image; + } + + public override void Style () + { + image.sprite = style.sprite; + image.color = style.color ?? UnityEngine.Color.white; + + toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; + toggle.transition = Selectable.Transition.ColorTint; + } + + void onValueChanged (bool on) + { + if (on) { + Select (); + } + } + + public void Select () + { + category.Select (); + } + + public void SelectCategory () + { + toggle.isOn = true; + } + + public ELPartCategoryView Group (ToggleGroup group) + { + toggle.group = group; + return this; + } + + public ELPartCategoryView Category (ELPartCategory category) + { + this.category = category; + image.sprite = category.offIcon; + style.sprite = image.sprite; + icon.image.sprite = category.onIcon; + return this; + } + +#region ILayoutElement + Vector2 minSize; + Vector2 preferredSize; + + public void CalculateLayoutInputHorizontal() + { + minSize = Vector2.zero; + float i, s; + i = image.preferredWidth; + s = icon.image.preferredWidth; + preferredSize.x = Mathf.Max (i, s); + } + + public void CalculateLayoutInputVertical() + { + float i, s; + i = image.preferredHeight; + s = icon.image.preferredHeight; + preferredSize.y = Mathf.Max (i, s); + } + + public int layoutPriority { get { return 0; } } + public float minWidth { get { return minSize.x; } } + public float preferredWidth { get { return preferredSize.x; } } + public float flexibleWidth { get { return -1; } } + public float minHeight { get { return minSize.y; } } + public float preferredHeight { get { return preferredSize.y; } } + public float flexibleHeight { get { return -1; } } +#endregion + } +} diff --git a/Source/UI/PartItemView.cs b/Source/UI/PartItemView.cs new file mode 100644 index 00000000..9108fbb4 --- /dev/null +++ b/Source/UI/PartItemView.cs @@ -0,0 +1,114 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + class ELPartItemView : UIObject + { + AvailablePart availablePart; + Image background; + Toggle toggle; + GameObject partIcon; + + public Material []materials; + + public override void CreateUI () + { + background = gameObject.AddComponent (); + background.type = UnityEngine.UI.Image.Type.Sliced; + + toggle = gameObject.AddComponent (); + toggle.targetGraphic = background; + + this.Pivot (PivotPresets.MiddleCenter); + } + + public override void Style () + { + background.sprite = style.sprite; + background.color = style.color ?? UnityEngine.Color.white; + + toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; + toggle.transition = style.transition ?? Selectable.Transition.ColorTint; + if (style.stateSprites.HasValue) { + toggle.spriteState = style.stateSprites.Value; + } + } + + public ELPartItemView Group (ToggleGroup group) + { + toggle.group = group; + return this; + } + + protected override void OnDestroy () + { + Destroy (partIcon); + } + + public ELPartItemView OnValueCanged (UnityAction action) + { + toggle.onValueChanged.AddListener (action); + return this; + } + + public ELPartItemView AvailablePart (AvailablePart availablePart) + { + if (partIcon) { + Destroy (partIcon); + } + this.availablePart = availablePart; + partIcon = GameObject.Instantiate (availablePart.iconPrefab); + partIcon.transform.SetParent (rectTransform, false); + partIcon.transform.localPosition = new Vector3 (0, 0, -39); + partIcon.transform.localScale = new Vector3 (39, 39, 39); + var rot = Quaternion.Euler (-15, 0, 0); + rot = rot * Quaternion.Euler (0, -30, 0); + partIcon.transform.rotation = rot; + partIcon.SetActive(true); + int layer = LayerMask.NameToLayer ("UIAdditional"); + EL_Utils.SetLayer (partIcon, layer, true); + + materials = EL_Utils.CollectMaterials (partIcon); + + if (availablePart.Variants != null + && availablePart.Variants.Count > 0) { + var variant = availablePart.partPrefab.baseVariant; + ModulePartVariants.ApplyVariant (null, partIcon.transform, + variant, materials, true); + } + return this; + } + } +} diff --git a/Source/UI/PartList.cs b/Source/UI/PartList.cs new file mode 100644 index 00000000..cfe2412a --- /dev/null +++ b/Source/UI/PartList.cs @@ -0,0 +1,77 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; +using TMPro; + +using KSP.IO; +using KSP.UI; +using KSP.UI.Screens; + +using KodeUI; + +using ExtraplanetaryLaunchpads_KACWrapper; + +namespace ExtraplanetaryLaunchpads { + + class ELPartList : List, UIKit.IListObject + { + ToggleGroup group; + + public UnityAction onSelected { get; set; } + public Layout Content { get; set; } + public RectTransform RectTransform + { + get { return Content.rectTransform; } + } + + public void Create (int index) + { + Content + .Add () + .Group (group) + .OnValueCanged (on => select (index, on)) + .AvailablePart (this[index]) + .Finish () + ; + } + + public void Update (GameObject obj, int index) + { + var item = obj.GetComponent (); + item.AvailablePart (this[index]); + } + + public ELPartList (ToggleGroup group) + { + this.group = group; + } + + void select (int index, bool on) + { + if (on) { + onSelected.Invoke (this[index]); + } + } + } +} diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 93c5b620..ac0cdd6c 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -60,319 +60,6 @@ public class ELPartSelector : Layout PartCategories.none, }; -#region ELPartCategory - class ELPartCategory - { - public delegate void CategorySelectedCallback (PartCategories category); - public CategorySelectedCallback CategorySelected; - public Sprite onIcon { get; private set; } - public Sprite offIcon { get; private set; } - public PartCategories category { get; private set; } - - static Sprite []elFilterSprites = new Sprite[2]; - static string []elFilterNames = { - "icon_filter_n", - "icon_filter_s" - }; - - static Sprite FindSprite (PartCategories category, bool on) - { - int ind = on ? 1 : 0; - if (elFilterSprites[ind] == null) { - string path = $"GameData/ExtraplanetaryLaunchpads/Textures/{elFilterNames[ind]}.png"; - var tex = new Texture2D (32, 32, TextureFormat.ARGB32, false); - bool ok = EL_Utils.LoadImage (ref tex, path); - elFilterSprites[ind] = EL_Utils.MakeSprite (tex); - Debug.Log ($"[ELPartCategory] FindSprite {category} {path} {ok}"); - } - return elFilterSprites[ind]; - } - - public ELPartCategory (PartCategories category) - { - Debug.Log ($"[ELPartCategory] {category}"); - this.category = category; - onIcon = FindSprite (category, true); - offIcon = FindSprite (category, false); - } - - public void Select () - { - CategorySelected (category); - } - -#region ELPartCategory.List - public class List : List, UIKit.IListObject - { - ToggleGroup group; - public Layout Content { get; set; } - public RectTransform RectTransform - { - get { return Content.rectTransform; } - } - - public void Create (int index) - { - Content - .Add () - .Group (group) - .Category (this[index]) - .Finish () - ; - } - - public void Update (GameObject obj, int index) - { - var view = obj.GetComponent (); - view.Category (this[index]); - } - - public List (ToggleGroup group) - { - this.group = group; - } - - public void Select (PartCategories category) - { - group.SetAllTogglesOff (false); - for (int i = Content.rectTransform.childCount; i-- > 0; ) { - var child = Content.rectTransform.GetChild (i); - var view = child.GetComponent (); - if (view.category.category == category) { - view.SelectCategory (); - break; - } - } - } - } -#endregion - } -#endregion - -#region ELPartCategoryView - class ELPartCategoryView : UIObject, ILayoutElement - { - Toggle toggle; - Image image; - UIImage icon; - - public ELPartCategory category { get; private set; } - - public override void CreateUI () - { - image = gameObject.AddComponent (); - image.type = UnityEngine.UI.Image.Type.Sliced; - - this.PreferredSize (32, 32) - .Add (out icon) - .Anchor (AnchorPresets.StretchAll) - .Pivot (PivotPresets.MiddleCenter) - .SizeDelta(0, 0) - .Finish () - ; - - toggle = gameObject.AddComponent (); - toggle.onValueChanged.AddListener (onValueChanged); - toggle.targetGraphic = image; - toggle.graphic = icon.image; - } - - public override void Style () - { - image.sprite = style.sprite; - image.color = style.color ?? UnityEngine.Color.white; - - toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; - toggle.transition = Selectable.Transition.ColorTint; - } - - void onValueChanged (bool on) - { - if (on) { - Select (); - } - } - - public void Select () - { - category.Select (); - } - - public void SelectCategory () - { - toggle.isOn = true; - } - - public ELPartCategoryView Group (ToggleGroup group) - { - toggle.group = group; - return this; - } - - public ELPartCategoryView Category (ELPartCategory category) - { - this.category = category; - image.sprite = category.offIcon; - style.sprite = image.sprite; - icon.image.sprite = category.onIcon; - return this; - } - -#region ILayoutElement - Vector2 minSize; - Vector2 preferredSize; - - public void CalculateLayoutInputHorizontal() - { - minSize = Vector2.zero; - float i, s; - i = image.preferredWidth; - s = icon.image.preferredWidth; - preferredSize.x = Mathf.Max (i, s); - } - - public void CalculateLayoutInputVertical() - { - float i, s; - i = image.preferredHeight; - s = icon.image.preferredHeight; - preferredSize.y = Mathf.Max (i, s); - } - - public int layoutPriority { get { return 0; } } - public float minWidth { get { return minSize.x; } } - public float preferredWidth { get { return preferredSize.x; } } - public float flexibleWidth { get { return -1; } } - public float minHeight { get { return minSize.y; } } - public float preferredHeight { get { return preferredSize.y; } } - public float flexibleHeight { get { return -1; } } -#endregion - } -#endregion - -#region ELPartItemView - class ELPartItemView : UIObject - { - AvailablePart availablePart; - Image background; - Toggle toggle; - GameObject partIcon; - - public Material []materials; - - public override void CreateUI () - { - background = gameObject.AddComponent (); - background.type = UnityEngine.UI.Image.Type.Sliced; - - toggle = gameObject.AddComponent (); - toggle.targetGraphic = background; - - this.Pivot (PivotPresets.MiddleCenter); - } - - public override void Style () - { - background.sprite = style.sprite; - background.color = style.color ?? UnityEngine.Color.white; - - toggle.colors = style.stateColors ?? ColorBlock.defaultColorBlock; - toggle.transition = style.transition ?? Selectable.Transition.ColorTint; - if (style.stateSprites.HasValue) { - toggle.spriteState = style.stateSprites.Value; - } - } - - public ELPartItemView Group (ToggleGroup group) - { - toggle.group = group; - return this; - } - - protected override void OnDestroy () - { - Destroy (partIcon); - } - - public ELPartItemView OnValueCanged (UnityAction action) - { - toggle.onValueChanged.AddListener (action); - return this; - } - - public ELPartItemView AvailablePart (AvailablePart availablePart) - { - if (partIcon) { - Destroy (partIcon); - } - this.availablePart = availablePart; - partIcon = GameObject.Instantiate (availablePart.iconPrefab); - partIcon.transform.SetParent (rectTransform, false); - partIcon.transform.localPosition = new Vector3 (0, 0, -39); - partIcon.transform.localScale = new Vector3 (39, 39, 39); - var rot = Quaternion.Euler (-15, 0, 0); - rot = rot * Quaternion.Euler (0, -30, 0); - partIcon.transform.rotation = rot; - partIcon.SetActive(true); - int layer = LayerMask.NameToLayer ("UIAdditional"); - EL_Utils.SetLayer (partIcon, layer, true); - - materials = EL_Utils.CollectMaterials (partIcon); - - if (availablePart.Variants != null - && availablePart.Variants.Count > 0) { - var variant = availablePart.partPrefab.baseVariant; - ModulePartVariants.ApplyVariant (null, partIcon.transform, - variant, materials, true); - } - return this; - } - } -#endregion - -#region ELPartList - class ELPartList : List, UIKit.IListObject - { - ToggleGroup group; - - public UnityAction onSelected { get; set; } - public Layout Content { get; set; } - public RectTransform RectTransform - { - get { return Content.rectTransform; } - } - - public void Create (int index) - { - Content - .Add () - .Group (group) - .OnValueCanged (on => select (index, on)) - .AvailablePart (this[index]) - .Finish () - ; - } - - public void Update (GameObject obj, int index) - { - var item = obj.GetComponent (); - item.AvailablePart (this[index]); - } - - public ELPartList (ToggleGroup group) - { - this.group = group; - } - - void select (int index, bool on) - { - if (on) { - onSelected.Invoke (this[index]); - } - } - } -#endregion - SelectPartCallback OnPartSelected; CancelledCallback OnPartCancelled; From b37b98085d4a80f8e9c07a6e8978f54437695db4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 21 Oct 2020 15:31:42 +0900 Subject: [PATCH 102/150] Do another cleanup of using Ugh, need to remember to clean them out each time I copy a file for the basic structure. --- Source/UI/BuildCraftView.cs | 4 ---- Source/UI/CraftBrowser.cs | 12 ---------- Source/UI/CraftSelector.cs | 10 --------- Source/UI/CraftThumb.cs | 4 ---- Source/UI/CraftThumbManager.cs | 3 --- Source/UI/CraftTypeSelector.cs | 1 - Source/UI/PartCategory.cs | 11 --------- Source/UI/PartCategoryView.cs | 12 ---------- Source/UI/PartEditorView.cs | 41 ++++++++++++++++++++++++++-------- Source/UI/PartEditorWindow.cs | 10 --------- Source/UI/PartItemView.cs | 11 --------- Source/UI/PartList.cs | 10 --------- Source/UI/PartListLight.cs | 1 - Source/UI/PartPreview.cs | 6 ----- Source/UI/PartSelector.cs | 10 --------- 15 files changed, 32 insertions(+), 114 deletions(-) diff --git a/Source/UI/BuildCraftView.cs b/Source/UI/BuildCraftView.cs index 794249c7..fabc0dff 100644 --- a/Source/UI/BuildCraftView.cs +++ b/Source/UI/BuildCraftView.cs @@ -16,7 +16,6 @@ You should have received a copy of the GNU General Public License . */ using System; -using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -25,9 +24,6 @@ You should have received a copy of the GNU General Public License using KodeUI; -//using KSP.IO; -using CBDLoadType = KSP.UI.Screens.CraftBrowserDialog.LoadType; - namespace ExtraplanetaryLaunchpads { public class ELBuildCraftView : Layout diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index c10bc57c..f95338d0 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -15,22 +15,10 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; using TMPro; -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { public enum ELCraftType { VAB, SPH, SubAss, Part }; diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index 08cd5a23..d3ca47aa 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -15,23 +15,13 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using System.IO; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; using TMPro; -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { public class ELCraftSelector : Layout diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index dd1a4cdf..a7d4aac5 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -15,13 +15,9 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using System.IO; using System.Collections; -using System.Collections.Generic; using UnityEngine; -using UnityEngine.Events; -using TMPro; using KodeUI; diff --git a/Source/UI/CraftThumbManager.cs b/Source/UI/CraftThumbManager.cs index ed646bb2..e20552b9 100644 --- a/Source/UI/CraftThumbManager.cs +++ b/Source/UI/CraftThumbManager.cs @@ -16,12 +16,9 @@ You should have received a copy of the GNU General Public License . */ using System; -using System.IO; -using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; -using TMPro; using KodeUI; diff --git a/Source/UI/CraftTypeSelector.cs b/Source/UI/CraftTypeSelector.cs index f5bdfca1..2d21434f 100644 --- a/Source/UI/CraftTypeSelector.cs +++ b/Source/UI/CraftTypeSelector.cs @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using UnityEngine; using UnityEngine.UI; using UnityEngine.Events; diff --git a/Source/UI/PartCategory.cs b/Source/UI/PartCategory.cs index d88fa10a..db9634d6 100644 --- a/Source/UI/PartCategory.cs +++ b/Source/UI/PartCategory.cs @@ -15,23 +15,12 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; using System.Collections.Generic; -using System.Linq; using UnityEngine; -using UnityEngine.Events; using UnityEngine.UI; -using TMPro; - -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { class ELPartCategory diff --git a/Source/UI/PartCategoryView.cs b/Source/UI/PartCategoryView.cs index ecaa4b27..a45f94d4 100644 --- a/Source/UI/PartCategoryView.cs +++ b/Source/UI/PartCategoryView.cs @@ -15,23 +15,11 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; using UnityEngine; -using UnityEngine.Events; using UnityEngine.UI; -using TMPro; - -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { class ELPartCategoryView : UIObject, ILayoutElement diff --git a/Source/UI/PartEditorView.cs b/Source/UI/PartEditorView.cs index d236096c..14439ec0 100644 --- a/Source/UI/PartEditorView.cs +++ b/Source/UI/PartEditorView.cs @@ -15,18 +15,10 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; +using System.Collections; using UnityEngine; -using UnityEngine.UI; using TMPro; -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - using KodeUI; namespace ExtraplanetaryLaunchpads { @@ -141,6 +133,36 @@ public ELPartEditorView SetDelegates (SelectPartCallback onSelectPart, return this; } + void BuildTweakers () + { + Debug.Log ($"[ELPartEditorView] BuildTweakers"); + for (int i = 0; i < part.Fields.Count; i++) { + var f = part.Fields[i]; + if (!f.guiActiveEditor) { + continue; + } + Debug.Log ($" {f.guiName} {f.guiActiveEditor} ucf:{f.uiControlFlight} uce:{f.uiControlEditor}"); + } + for (int i = 0; i < part.Modules.Count; i++) { + var m = part.Modules[i]; + Debug.Log ($" {m.ClassName}"); + for (int j = 0; j < m.Fields.Count; j++) { + var f = m.Fields[j]; + if (!f.guiActiveEditor) { + continue; + } + Debug.Log ($" {f.guiName} {f.guiActiveEditor} ucf:{f.uiControlFlight} uce:{f.uiControlEditor}"); + } + } + } + + IEnumerator WaitAndBuildTweakers () + { + yield return null; + + BuildTweakers (); + } + public void EditPart (AvailablePart availablePart) { SetActive (true); @@ -151,6 +173,7 @@ public void EditPart (AvailablePart availablePart) EL_Utils.RemoveColliders (part.gameObject); part.gameObject.SetActive (true); partPreview.Part (part); + StartCoroutine (WaitAndBuildTweakers ()); } else { if (!part) { Close (); diff --git a/Source/UI/PartEditorWindow.cs b/Source/UI/PartEditorWindow.cs index 50c44690..39987d63 100644 --- a/Source/UI/PartEditorWindow.cs +++ b/Source/UI/PartEditorWindow.cs @@ -15,18 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; using TMPro; -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - using KodeUI; namespace ExtraplanetaryLaunchpads { diff --git a/Source/UI/PartItemView.cs b/Source/UI/PartItemView.cs index 9108fbb4..12cfe719 100644 --- a/Source/UI/PartItemView.cs +++ b/Source/UI/PartItemView.cs @@ -15,23 +15,12 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; -using TMPro; - -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { class ELPartItemView : UIObject diff --git a/Source/UI/PartList.cs b/Source/UI/PartList.cs index cfe2412a..04245461 100644 --- a/Source/UI/PartList.cs +++ b/Source/UI/PartList.cs @@ -15,23 +15,13 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; using System.Collections.Generic; -using System.Linq; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; -using TMPro; - -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { class ELPartList : List, UIKit.IListObject diff --git a/Source/UI/PartListLight.cs b/Source/UI/PartListLight.cs index cc3900e4..60ea5996 100644 --- a/Source/UI/PartListLight.cs +++ b/Source/UI/PartListLight.cs @@ -15,7 +15,6 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; using UnityEngine; namespace ExtraplanetaryLaunchpads { diff --git a/Source/UI/PartPreview.cs b/Source/UI/PartPreview.cs index f4756aba..e80213a0 100644 --- a/Source/UI/PartPreview.cs +++ b/Source/UI/PartPreview.cs @@ -15,14 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; -using System.Collections; -using System.Collections.Generic; using UnityEngine; -using UnityEngine.Events; using UnityEngine.EventSystems; -using TMPro; using KodeUI; diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index ac0cdd6c..4a48556d 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -15,23 +15,13 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ -using System; -using System.IO; using System.Collections.Generic; -using System.Linq; using UnityEngine; -using UnityEngine.Events; using UnityEngine.UI; using TMPro; -using KSP.IO; -using KSP.UI; -using KSP.UI.Screens; - using KodeUI; -using ExtraplanetaryLaunchpads_KACWrapper; - namespace ExtraplanetaryLaunchpads { using TTC = KSP.UI.Screens.Editor.PartListTooltipController; From 05a9c6494d3b7e7019deea62d25d52f02ecfde75 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 23 Oct 2020 17:45:24 +0900 Subject: [PATCH 103/150] Implement saving of the edited part Of course, other than name and description, actual editing is not working, and only semi-surprising is that the part preview orientation affects the built part orientation, but the basics are working. Lots of bugs to fix, though. --- Source/UI/PartEditorView.cs | 30 ++++++++++++++++++++++++++++++ Source/UI/PartSelector.cs | 29 ----------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/Source/UI/PartEditorView.cs b/Source/UI/PartEditorView.cs index 14439ec0..f8b175c8 100644 --- a/Source/UI/PartEditorView.cs +++ b/Source/UI/PartEditorView.cs @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ +using System; +using System.IO; using System.Collections; using UnityEngine; using TMPro; @@ -27,6 +29,7 @@ public class ELPartEditorView : Layout { ELPartPreview partPreview; VerticalLayout tweakables; + UIInputField nameInput; UIInputField descriptionInput; Part part; @@ -78,6 +81,11 @@ public override void CreateUI () .PreferredSize (256, 256) .Finish () .Finish () + .Add (out nameInput) + .OnFocusGained (SetControlLock) + .OnFocusLost (ClearControlLock) + .FlexibleLayout (true, false) + .Finish () .Add (out descriptionInput) .LineType (TMP_InputField.LineType.MultiLineNewline) .OnFocusGained (SetControlLock) @@ -110,6 +118,26 @@ void SelectPart () void Save () { + string name = nameInput.text; + string description = descriptionInput.text; + var ship = new ShipConstruct (name, description, part); + ConfigNode node = ship.SaveShip (); + //Debug.Log ($"[ELPartEditorView] Save {node}"); + + string basePath = KSPUtil.ApplicationRootPath; + string profile = HighLogic.SaveFolder; + string saveDir = "Parts/"; + string craft = "autopart.craft"; + if (!String.IsNullOrEmpty (name)) { + craft = $"{name}.craft"; + } + string dir = $"{basePath}saves/{profile}/{saveDir}"; + string fullPath = $"{dir}{craft}"; + //Debug.Log ($"[ELPartSelector] LoadPart {part.partInfo.title} {fullPath}"); + if (!Directory.Exists (dir)) { + Directory.CreateDirectory (dir); + } + node.Save (fullPath); } void SaveAndClose () @@ -183,6 +211,7 @@ public void EditPart (AvailablePart availablePart) public void EditPart (ELCraftItem editPart) { + nameInput.text = "Unnamed part"; descriptionInput.text = "EL constructed part"; if (part) { Destroy (part.gameObject); @@ -191,6 +220,7 @@ public void EditPart (ELCraftItem editPart) partPreview.AvailablePart (null); if (editPart != null) { var node = editPart.node; + nameInput.text = editPart.name; if (node.HasValue ("description")) { string description = node.GetValue ("description"); descriptionInput.text = description.Replace ('¨', '\n'); diff --git a/Source/UI/PartSelector.cs b/Source/UI/PartSelector.cs index 4a48556d..7ad1351b 100644 --- a/Source/UI/PartSelector.cs +++ b/Source/UI/PartSelector.cs @@ -331,34 +331,5 @@ public void SetSelectedPart (AvailablePart availablePart) categoryList.Select (cat); UpdateSelectedPart (availablePart); } - - static ConfigNode CreateShip(AvailablePart availablePart) - { - var part = GameObject.Instantiate (availablePart.partPrefab) as Part; - ConfigNode node = new ConfigNode(); - - node.AddValue("ship", availablePart.title); - node.AddValue("version", Versioning.version_major + "." + Versioning.version_minor + "." + Versioning.Revision); - node.AddValue("description", "EL constructed part"); - node.AddValue("type", "VAB"); - node.AddValue("persistentId", 0); - node.AddValue("rot", Quaternion.identity); - node.AddValue("vesselType", part.vesselType); - - part.onBackup(); - ConfigNode partNode = node.AddNode("PART"); - - partNode.AddValue("part", part.partInfo.name + "_" + part.craftID); - partNode.AddValue("partName", part.partName); - partNode.AddValue("persistentId", part.persistentId); - partNode.AddValue("pos", Vector3.zero); - partNode.AddValue("attPos", Vector3.zero); - partNode.AddValue("attPos0", Vector3.zero); - partNode.AddValue("rot", Quaternion.identity); - partNode.AddValue("attRot", Quaternion.identity); - partNode.AddValue("attRot0", Quaternion.identity); - - return node; - } } } From 08f72a75574d3edd72969377b356ba318fd258c3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 10:49:36 +0900 Subject: [PATCH 104/150] Create sprites for EL's UI While EL could use KodeUI's sprites directly, this allows for better independence and EL needed some custom icons anyway. --- Assets/DefaultSkin.cfg | 375 +++++++++++++++++++++++++++++++++++++++ Assets/Makefile | 48 ++++- Assets/ui_background.svg | 87 +++++++++ Assets/ui_button.svg | 118 ++++++++++++ Assets/ui_checkmark.svg | 105 +++++++++++ Assets/ui_dropdown.svg | 92 ++++++++++ Assets/ui_leftturn.svg | 72 ++++++++ Assets/ui_rightturn.svg | 72 ++++++++ Assets/ui_toggle_off.svg | 120 +++++++++++++ Assets/ui_toggle_on.svg | 120 +++++++++++++ 10 files changed, 1205 insertions(+), 4 deletions(-) create mode 100644 Assets/DefaultSkin.cfg create mode 100644 Assets/ui_background.svg create mode 100644 Assets/ui_button.svg create mode 100644 Assets/ui_checkmark.svg create mode 100644 Assets/ui_dropdown.svg create mode 100644 Assets/ui_leftturn.svg create mode 100644 Assets/ui_rightturn.svg create mode 100644 Assets/ui_toggle_off.svg create mode 100644 Assets/ui_toggle_on.svg diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg new file mode 100644 index 00000000..698c4df5 --- /dev/null +++ b/Assets/DefaultSkin.cfg @@ -0,0 +1,375 @@ +KodeUI_Skin { + name = default + Style { + name = default + } + Style { + name = ScrollView + sprite = EL.Default.background + } + Style { + name = Viewport + sprite = EL.Default.mask + } + Style { + name = Scrollbar + sprite = EL.Default.background + } + Style { + name = Scrollbar.Handle + sprite = EL.Default.background + } + Style { + name = TabItemView + sprite = EL.Default.background + } + Style { + name = TabItemView.Label + color = 1, 1, 1, 1 + } + Style { + name = UIButton + sprite = EL.Default.button + } + Style { + name = UIDropdown + sprite = EL.Default.background + } + Style { + name = UIDropdown.Label + color = 1, 1, 1, 1 + } + Style { + name = UIDropdown.Arrow + sprite = EL.Default.dropdown + } + Style { + name = UIDropdown.Template + sprite = EL.Default.background + } + Style { + name = UIDropdown.Scrollbar + sprite = EL.Default.background + } + Style { + name = UIDropdown.Scrollbar.Handle + sprite = EL.Default.background + } + Style { + name = UIDropdown.Viewport + sprite = EL.Default.mask + } + Style { + name = UIDropdown.Item + sprite = EL.Default.background + } + Style { + name = UIDropdown.Item.CheckMark + sprite = EL.Default.toggle_on + } + Style { + name = UIDropdown.Item.ItemText + sprite = EL.Default.background + } + Style { + name = UIInputField + sprite = EL.Default.background + } + Style { + name = UISlider + stateColors { + normalColor = 1, 1, 1, 0.8 + colorMultiplier = 1.25 + } + } + Style { + name = UISlider.Background + sprite = EL.Default.background + color = 0.5, 0.5, 0.5, 0.5 + } + Style { + name = UISlider.Fill + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = UISlider.Handle + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = UIText + color = 1, 1, 1, 1 + } + Style { + name = UIToggle + sprite = EL.Default.toggle_off + } + Style { + name = UIToggle.CheckMark + sprite = EL.Default.toggle_on + } + Style { + name = Window + sprite = EL.Default.window + } + + Style { + name = ELPartEditorWindow + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELPartItemView + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELPartCategoryView + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELCraftItemView + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELCraftBrowser + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELRenameDialog + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELShipInfo + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = ELMainWindow + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = Productivity + sprite = EL.Default.background + color = 1, 1, 1, 1 + } + Style { + name = PadSelector + sprite = EL.Default.background + } + Style { + name = PadSelector.Label + sprite = EL.Default.background + } + Style { + name = PadSelector.Arrow + sprite = EL.Default.dropdown + } + Style { + name = PadSelector.Template + sprite = EL.Default.background + } + Style { + name = PadSelector.Scrollbar + sprite = EL.Default.background + } + Style { + name = PadSelector.Scrollbar.Handle + sprite = EL.Default.background + } + Style { + name = PadSelector.Viewport + sprite = EL.Default.mask + } + Style { + name = PadSelector.Item + sprite = EL.Default.background + } + Style { + name = PadSelector.Item.CheckMark + sprite = EL.Default.toggle_on + } + Style { + name = PadSelector.Item.ItemText + sprite = EL.Default.background + } + Style { + name = SiteSelector + sprite = EL.Default.background + } + Style { + name = SiteSelector.Label + sprite = EL.Default.background + } + Style { + name = SiteSelector.Arrow + sprite = EL.Default.dropdown + } + Style { + name = SiteSelector.Template + sprite = EL.Default.background + } + Style { + name = SiteSelector.Scrollbar + sprite = EL.Default.background + } + Style { + name = SiteSelector.Scrollbar.Handle + sprite = EL.Default.background + } + Style { + name = SiteSelector.Viewport + sprite = EL.Default.mask + } + Style { + name = SiteSelector.Item + sprite = EL.Default.background + } + Style { + name = SiteSelector.Item.CheckMark + sprite = EL.Default.toggle_on + } + Style { + name = SiteSelector.Item.ItemText + sprite = EL.Default.background + } + Style { + name = HighlightPad + sprite = EL.Default.toggle_off + } + Style { + name = HighlightPad.CheckMark + sprite = EL.Default.toggle_on + } + Style { + name = ResourceFraction + stateColors { + normalColor = 1, 1, 1, 0.8 + colorMultiplier = 1.25 + } + } + Style { + name = ResourceFraction.Background + sprite = EL.Default.background + color = 1, 0.890196078, 0.329411765, 1 + } + Style { + name = ResourceFraction.Fill + sprite = EL.Default.background + color = 0, 1, 0.0470588235, 1 + } + Style { + name = ResourceFraction.Handle + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 + } + Style { + name = AmountsPanel + sprite = EL.Default.background + } +} + +KodeUI_Sprite { + name = EL.Default.background + textureUrl = ExtraplanetaryLaunchpads/UI/ui_background + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.button + textureUrl = ExtraplanetaryLaunchpads/UI/ui_button + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = FullRect + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.checkmark + textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_on + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.dropdown + textureUrl = ExtraplanetaryLaunchpads/UI/ui_dropdown + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.leftturn + textureUrl = ExtraplanetaryLaunchpads/UI/ui_leftturn + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 12, 12, 12, 12 +} + +KodeUI_Sprite { + name = EL.Default.mask + textureUrl = ExtraplanetaryLaunchpads/UI/ui_background + rect = 15, 15, 2, 2 + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 0, 0, 0, 0 +} + +KodeUI_Sprite { + name = EL.Default.rightturn + textureUrl = ExtraplanetaryLaunchpads/UI/ui_rightturn + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 12, 12, 12, 12 +} + +KodeUI_Sprite { + name = EL.Default.toggle_off + textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_off + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} + +KodeUI_Sprite { + name = EL.Default.toggle_on + textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_on + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 5, 5, 5, 5 +} diff --git a/Assets/Makefile b/Assets/Makefile index c58bac53..19ba30fd 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -29,7 +29,22 @@ MISC := \ kairyuu_scaled.png \ plaque.png -all: ${ICONS} ${FLAGS} ${MISC} +UI_IMAGES := \ + ui_background.png \ + ui_button.png \ + ui_checkmark.png \ + ui_dropdown.png \ + ui_leftturn.png \ + ui_rightturn.png \ + ui_toggle_off.png \ + ui_toggle_on.png \ + $e + +UI_CFG := \ + DefaultSkin.cfg \ + $e + +all: ${ICONS} ${FLAGS} ${MISC} ${UI_IMAGES} info: @echo "Extraplanetary Launchpads Build Information" @@ -41,7 +56,7 @@ info: @echo " zip: ${ZIP}" @echo " KSP Data: ${KSPDIR}" -GUI_ICONS = \ +GUI_ICONS := \ gui_background.png \ gui_flat.png \ gui_raised.png \ @@ -75,8 +90,32 @@ icon_filter_s.png: EL_filter.svg ELGenericCraftThumb.png: EL_UntitledSpacecraft.svg inkscape --export-width=256 --export-height=256 --export-background='#000000' --export-background-opacity=0 --export-type=png -o $@ $^ +ui_background.png: ui_background.svg + inkscape --export-width=32 --export-height=32 --export-type=png -o $@ $^ + +ui_button.png: ui_button.svg + inkscape --export-width=16 --export-height=16 --export-type=png -o $@ $^ + +ui_checkmark.png: ui_checkmark.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_dropdown.png: ui_dropdown.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_leftturn.png: ui_leftturn.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_rightturn.png: ui_rightturn.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_toggle_off.png: ui_toggle_off.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_toggle_on.png: ui_toggle_on.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + clean: - rm -f ${ICONS} ${FLAGS} ${MISC} ${GUI_ICONS} + rm -f ${ICONS} ${FLAGS} ${MISC} ${GUI_ICONS} ${UI_IMAGES} install: all mkdir -p ${MODGAMEDATA}/Agencies ${MODGAMEDATA}/Flags @@ -84,6 +123,7 @@ install: all cp nightheron.png ${MODGAMEDATA}/Flags mkdir -p ${MODGAMEDATA}/Textures cp ELGenericCraftThumb.png icon_button.png icon_filter*.png plaque.png ${MODGAMEDATA}/Textures - #cp ${GUI_ICONS} ${MODGAMEDATA}/Textures + mkdir -p ${MODGAMEDATA}/UI + cp ${UI_CFG} ${UI_IMAGES} ${MODGAMEDATA}/UI .PHONY: all clean install diff --git a/Assets/ui_background.svg b/Assets/ui_background.svg new file mode 100644 index 00000000..9eb4eebd --- /dev/null +++ b/Assets/ui_background.svg @@ -0,0 +1,87 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_button.svg b/Assets/ui_button.svg new file mode 100644 index 00000000..91d3ec44 --- /dev/null +++ b/Assets/ui_button.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_checkmark.svg b/Assets/ui_checkmark.svg new file mode 100644 index 00000000..6ab85908 --- /dev/null +++ b/Assets/ui_checkmark.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_dropdown.svg b/Assets/ui_dropdown.svg new file mode 100644 index 00000000..9ab7927f --- /dev/null +++ b/Assets/ui_dropdown.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/Assets/ui_leftturn.svg b/Assets/ui_leftturn.svg new file mode 100644 index 00000000..3ab52b71 --- /dev/null +++ b/Assets/ui_leftturn.svg @@ -0,0 +1,72 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_rightturn.svg b/Assets/ui_rightturn.svg new file mode 100644 index 00000000..169c7d6d --- /dev/null +++ b/Assets/ui_rightturn.svg @@ -0,0 +1,72 @@ + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/Assets/ui_toggle_off.svg b/Assets/ui_toggle_off.svg new file mode 100644 index 00000000..d5994c54 --- /dev/null +++ b/Assets/ui_toggle_off.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_toggle_on.svg b/Assets/ui_toggle_on.svg new file mode 100644 index 00000000..a04e1bb8 --- /dev/null +++ b/Assets/ui_toggle_on.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + From 7987aa19500d0957c1767d6d2714056d5401c2ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 11:21:31 +0900 Subject: [PATCH 105/150] Remove some hard-coded backgrounds And hook up the left/right turn arrows --- Assets/DefaultSkin.cfg | 4 ++++ Source/UI/BuildCraftView.cs | 2 -- Source/UI/BuildView.cs | 2 -- Source/UI/PadLaunchpadView.cs | 5 ++--- Source/UI/PadSurveyView.cs | 1 - Source/UI/PadView.cs | 1 - Source/UI/ResourceManagerView.cs | 2 -- Source/UI/TransferView.cs | 2 -- 8 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index 698c4df5..e1821b5e 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -27,6 +27,10 @@ KodeUI_Skin { name = TabItemView.Label color = 1, 1, 1, 1 } + Style { + name = LayoutPanel + sprite = EL.Default.button + } Style { name = UIButton sprite = EL.Default.button diff --git a/Source/UI/BuildCraftView.cs b/Source/UI/BuildCraftView.cs index fabc0dff..79b92cea 100644 --- a/Source/UI/BuildCraftView.cs +++ b/Source/UI/BuildCraftView.cs @@ -149,8 +149,6 @@ public override void CreateUI() .Finish () .Finish () .Add() - .Background("KodeUI/Default/background") - .BackgroundColor(UnityEngine.Color.white) .Vertical() .Padding(8) .ControlChildSize(true, true) diff --git a/Source/UI/BuildView.cs b/Source/UI/BuildView.cs index fbb983eb..080785d4 100644 --- a/Source/UI/BuildView.cs +++ b/Source/UI/BuildView.cs @@ -136,8 +136,6 @@ public override void CreateUI() .ChildForceExpand(false,false) .Add() - .Background("KodeUI/Default/background") - .BackgroundColor(UnityEngine.Color.white) .Vertical() .Padding(8) .ControlChildSize(true, true) diff --git a/Source/UI/PadLaunchpadView.cs b/Source/UI/PadLaunchpadView.cs index 925c3b41..87e8801b 100644 --- a/Source/UI/PadLaunchpadView.cs +++ b/Source/UI/PadLaunchpadView.cs @@ -40,9 +40,8 @@ public override void CreateUI() .ChildForceExpand (false, false) .Anchor (AnchorPresets.StretchAll) .SizeDelta (0, 0) - .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) .Add (out leftButton)//, "RotateLeft") FIXME - .Text ("<-") + .Image (SpriteLoader.GetSprite ("EL.Default.leftturn")) .OnClick (RotateLeft) .FlexibleLayout (false, true) .SizeDelta (0, 0) @@ -53,7 +52,7 @@ public override void CreateUI() .FlexibleLayout (true, true) .Finish () .Add (out rightButton)//, "RotateRight") FIXME - .Text ("->") + .Image (SpriteLoader.GetSprite ("EL.Default.rightturn")) .OnClick (RotateRight) .FlexibleLayout (false, true) .SizeDelta (0, 0) diff --git a/Source/UI/PadSurveyView.cs b/Source/UI/PadSurveyView.cs index 445ed748..5158bc52 100644 --- a/Source/UI/PadSurveyView.cs +++ b/Source/UI/PadSurveyView.cs @@ -47,7 +47,6 @@ public override void CreateUI() .ChildForceExpand (false, false) .Anchor (AnchorPresets.StretchAll) .SizeDelta (0, 0) - .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) .Add (out siteControl) .Horizontal () .ControlChildSize (true, true) diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 9507aa89..7246b341 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -118,7 +118,6 @@ public override void CreateUI() .ChildForceExpand (false, false) .Anchor (leftMin, leftMax) .SizeDelta (0, 0) - .Sprite(SpriteLoader.GetSprite("KodeUI/Default/background")) .Add (out padSelector, "PadSelector") .OnValueChanged (SelectPad) .FlexibleLayout (true, true) diff --git a/Source/UI/ResourceManagerView.cs b/Source/UI/ResourceManagerView.cs index bb2df901..0a4f9079 100644 --- a/Source/UI/ResourceManagerView.cs +++ b/Source/UI/ResourceManagerView.cs @@ -67,8 +67,6 @@ public override void CreateUI() .ChildForceExpand(false,false) .Add() - .Background("KodeUI/Default/background") - .BackgroundColor(UnityEngine.Color.white) .Vertical() .Padding(8) .ControlChildSize(true, true) diff --git a/Source/UI/TransferView.cs b/Source/UI/TransferView.cs index 0a99111b..266297ac 100644 --- a/Source/UI/TransferView.cs +++ b/Source/UI/TransferView.cs @@ -218,8 +218,6 @@ public override void CreateUI() .ChildForceExpand(false,false) .Add() - .Background("KodeUI/Default/background") - .BackgroundColor(UnityEngine.Color.white) .Vertical() .Padding(8) .ControlChildSize(true, true) From 9136d7aeb9d68fd3ff4b8d4863cc647a90a7f7ab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 13:00:53 +0900 Subject: [PATCH 106/150] Tweak the styles to look reasonable as a dark theme --- Assets/DefaultSkin.cfg | 74 ++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index e1821b5e..a5cfc83e 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -6,22 +6,27 @@ KodeUI_Skin { Style { name = ScrollView sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = Viewport sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 } Style { name = Scrollbar sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = Scrollbar.Handle sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = TabItemView sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = TabItemView.Label @@ -29,15 +34,18 @@ KodeUI_Skin { } Style { name = LayoutPanel - sprite = EL.Default.button + sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIButton sprite = EL.Default.button + color = 0.5, 0.5, 0.5, 1 } Style { name = UIDropdown sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Label @@ -46,38 +54,47 @@ KodeUI_Skin { Style { name = UIDropdown.Arrow sprite = EL.Default.dropdown + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Template sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Scrollbar sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Scrollbar.Handle sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Viewport sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Item sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIDropdown.Item.CheckMark - sprite = EL.Default.toggle_on + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 } Style { name = UIDropdown.Item.ItemText sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UIInputField sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = UISlider @@ -108,148 +125,168 @@ KodeUI_Skin { Style { name = UIToggle sprite = EL.Default.toggle_off + color = 0.25, 0.25, 0.25, 1 } Style { name = UIToggle.CheckMark sprite = EL.Default.toggle_on - } - Style { - name = Window - sprite = EL.Default.window + color = 0.25, 1, 0.25, 1 } Style { name = ELPartEditorWindow sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELPartItemView sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELPartCategoryView sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELCraftItemView sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELCraftBrowser sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELRenameDialog sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELShipInfo sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = ELMainWindow sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = Productivity sprite = EL.Default.background - color = 1, 1, 1, 1 + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Label sprite = EL.Default.background + color = 1, 1, 1, 1 } Style { name = PadSelector.Arrow sprite = EL.Default.dropdown + color = 1, 1, 1, 1 } Style { name = PadSelector.Template sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Scrollbar sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Scrollbar.Handle sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Viewport sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Item sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = PadSelector.Item.CheckMark - sprite = EL.Default.toggle_on + sprite = EL.Default.checkmark + color = 1, 1, 1, 1 } Style { name = PadSelector.Item.ItemText sprite = EL.Default.background + color = 1, 1, 1, 1 } Style { name = SiteSelector sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Label sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Arrow sprite = EL.Default.dropdown + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Template sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Scrollbar sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Scrollbar.Handle sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Viewport sprite = EL.Default.mask + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Item sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Item.CheckMark - sprite = EL.Default.toggle_on + sprite = EL.Default.checkmark + color = 0.25, 0.25, 0.25, 1 } Style { name = SiteSelector.Item.ItemText sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } Style { name = HighlightPad sprite = EL.Default.toggle_off + color = 0.25, 0.25, 0.25, 1 } Style { name = HighlightPad.CheckMark sprite = EL.Default.toggle_on + color = 0.25, 1, 0.25, 1 } Style { name = ResourceFraction @@ -276,6 +313,7 @@ KodeUI_Skin { Style { name = AmountsPanel sprite = EL.Default.background + color = 0.25, 0.25, 0.25, 1 } } @@ -303,7 +341,7 @@ KodeUI_Sprite { KodeUI_Sprite { name = EL.Default.checkmark - textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_on + textureUrl = ExtraplanetaryLaunchpads/UI/ui_checkmark //defaults to full image: rect = 0, 0, , //defaults to center of rect: pivot = 0.5, 0.5 pixelsPerUnit = 100 From 23025ab796c4f42b553ebb2424c522c9adf5f469 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 13:01:23 +0900 Subject: [PATCH 107/150] Switch to the mini toggle for the highlight pad toggle --- Source/UI/PadView.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 7246b341..7c131b52 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -58,7 +58,7 @@ private set { List padControls; UIDropdown padSelector; - UIToggle highlightPad; + MiniToggle highlightPad; ELPadLaunchpadView launchpadView; ELPadSurveyView surveyView; @@ -122,7 +122,7 @@ public override void CreateUI() .OnValueChanged (SelectPad) .FlexibleLayout (true, true) .Finish () - .Add (out highlightPad, "HighlightPad") + .Add (out highlightPad, "HighlightPad") .FlexibleLayout (false, true) .PreferredSize (25, 25) .Finish () From 9fbff2eb1a4e9a5e39ae2d8b2af0730463b06404 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 13:20:18 +0900 Subject: [PATCH 108/150] Use EL.Default as the skin name This keeps EL's skin separate from the default KodeUI skin. --- Assets/DefaultSkin.cfg | 2 +- Source/UI/CraftBrowser.cs | 1 + Source/UI/MainWindow.cs | 1 + Source/UI/PartEditorWindow.cs | 1 + Source/UI/RenameDialog.cs | 1 + Source/UI/ShipInfoWindow.cs | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index a5cfc83e..84eb67aa 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -1,5 +1,5 @@ KodeUI_Skin { - name = default + name = EL.Default Style { name = default } diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index f95338d0..1f7bd38e 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -48,6 +48,7 @@ public override void CreateUI () .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) .Pivot (PivotPresets.TopLeft) + .SetSkin ("EL.Default") .Add (out typeSelector) .OnSelectionChanged (CraftTypeSelected) .FlexibleLayout (true, true) diff --git a/Source/UI/MainWindow.cs b/Source/UI/MainWindow.cs index abee16f3..b8b6f2da 100644 --- a/Source/UI/MainWindow.cs +++ b/Source/UI/MainWindow.cs @@ -39,6 +39,7 @@ public override void CreateUI() .Anchor(AnchorPresets.MiddleCenter) .Pivot(PivotPresets.TopLeft) .PreferredWidth(695) + .SetSkin ("EL.Default") .Add (out tabController) .Horizontal () diff --git a/Source/UI/PartEditorWindow.cs b/Source/UI/PartEditorWindow.cs index 39987d63..1417a8f3 100644 --- a/Source/UI/PartEditorWindow.cs +++ b/Source/UI/PartEditorWindow.cs @@ -37,6 +37,7 @@ public override void CreateUI () .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) .Pivot (PivotPresets.MiddleCenter) + .SetSkin ("EL.Default") .Add (out partEditor) .SetDelegates (onSelectPart, onEditorClose) .Finish () diff --git a/Source/UI/RenameDialog.cs b/Source/UI/RenameDialog.cs index b33a6144..012e4575 100644 --- a/Source/UI/RenameDialog.cs +++ b/Source/UI/RenameDialog.cs @@ -47,6 +47,7 @@ public override void CreateUI() .Anchor (AnchorPresets.MiddleCenter) .Pivot (PivotPresets.TopLeft) .PreferredWidth (500) + .SetSkin ("EL.Default") .Add () .Horizontal () diff --git a/Source/UI/ShipInfoWindow.cs b/Source/UI/ShipInfoWindow.cs index 4b78105c..52a41e77 100644 --- a/Source/UI/ShipInfoWindow.cs +++ b/Source/UI/ShipInfoWindow.cs @@ -49,6 +49,7 @@ public override void CreateUI() .Anchor(AnchorPresets.MiddleCenter) .Pivot(PivotPresets.TopLeft) .PreferredWidth(350) + .SetSkin ("EL.Default") .Add (out dryMass) .Label (ELLocalization.DryMass) From 4ad758953444c2e9697afa343b0a168d088c0fe9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 14:33:20 +0900 Subject: [PATCH 109/150] Hook up the highlight pad toggle --- Source/Survey/SurveyStake.cs | 2 +- Source/UI/MiniToggle.cs | 6 ++++++ Source/UI/PadView.cs | 22 ++++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Source/Survey/SurveyStake.cs b/Source/Survey/SurveyStake.cs index 32472b48..5ace3a32 100644 --- a/Source/Survey/SurveyStake.cs +++ b/Source/Survey/SurveyStake.cs @@ -223,7 +223,7 @@ void UpdatePlaque () void CreateBackground (RectTransform parent) { - GameObject go = new GameObject ("Survey Plaque Bacground", + GameObject go = new GameObject ("Survey Plaque Background", typeof (RectTransform)); plaqueBackgroundRenderer = go.AddComponent (); plaqueBackgroundRenderer.SetAlpha (PlaqueAlpha); diff --git a/Source/UI/MiniToggle.cs b/Source/UI/MiniToggle.cs index 485c2d9c..d9320da2 100644 --- a/Source/UI/MiniToggle.cs +++ b/Source/UI/MiniToggle.cs @@ -27,6 +27,12 @@ public class MiniToggle : Layout { UIToggle toggle; + public bool isOn + { + get { return toggle.isOn; } + set { toggle.isOn = value; } + } + public bool interactable { get { return toggle.interactable; } diff --git a/Source/UI/PadView.cs b/Source/UI/PadView.cs index 7c131b52..cc2a94d4 100644 --- a/Source/UI/PadView.cs +++ b/Source/UI/PadView.cs @@ -123,6 +123,7 @@ public override void CreateUI() .FlexibleLayout (true, true) .Finish () .Add (out highlightPad, "HighlightPad") + .OnValueChanged (HighlightPad) .FlexibleLayout (false, true) .PreferredSize (25, 25) .Finish () @@ -149,11 +150,31 @@ public override void Style () void SelectPad (int index) { + HighlightPad (false); control = padControls[index]; worknet.selectedPad = control.builder.ID; + HighlightPad (highlightPad.isOn); UpdateMenus (gameObject.activeInHierarchy); } + void HighlightPad (bool on) + { + if (control != null) { + control.builder.Highlight (on); + } + } + + void Update () + { + // KSP's part highlighter forces highlighting off when the mouse + // is no longer hovering over the part, so need to turn it on each + // frame + // FIXME there might be a better way + if (control != null && highlightPad.isOn) { + control.builder.Highlight (true); + } + } + void UpdateMenus (bool visible) { if (padControls == null) { @@ -267,6 +288,7 @@ protected override void OnEnable () protected override void OnDisable () { base.OnDisable (); + HighlightPad (false); GameEvents.onVesselWasModified.Remove (onVesselWasModified); UpdateMenus (false); } From 09c22bc3fcdc824762ddba1848bd044cd5efc9f2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 15:02:07 +0900 Subject: [PATCH 110/150] Disallow thumb generation for stock or invalid craft --- Source/UI/CraftItem.cs | 27 ++++++++++++++++++++++++++- Source/UI/CraftSelector.cs | 12 ++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Source/UI/CraftItem.cs b/Source/UI/CraftItem.cs index 9c1c0d59..6101c6e1 100644 --- a/Source/UI/CraftItem.cs +++ b/Source/UI/CraftItem.cs @@ -29,6 +29,7 @@ namespace ExtraplanetaryLaunchpads { public class ELCraftItem { CraftProfileInfo info; + public List MissingParts { get; private set; } public string fullPath { get; private set; } public string name { get { return info.shipName; } } public string description { get { return info.description; } } @@ -38,6 +39,19 @@ public class ELCraftItem public string message { get; private set; } public string thumbPath { get; private set; } public ELCraftType type { get; private set; } + public bool isStock { get; private set; } + public bool canLoad + { + get { + if (info.compatibility != VersionCompareResult.COMPATIBLE) { + return false; + } + // EL might one day allow building from "stolen plans", so + // only actually missing parts blocks loading (tech and + // missions are irrelevant). + return MissingParts.Count == 0; + } + } ConfigNode _node; public ConfigNode node { @@ -50,7 +64,7 @@ public ConfigNode node set { _node = value; } } - public ELCraftItem (string craftPath, string metaPath, string thumbPath, ELCraftType craftType) + public ELCraftItem (string craftPath, string metaPath, string thumbPath, ELCraftType craftType, bool isStock) { fullPath = craftPath; info = new CraftProfileInfo (); @@ -62,9 +76,20 @@ public ELCraftItem (string craftPath, string metaPath, string thumbPath, ELCraft info.LoadDetailsFromCraftFile (node, craftPath); this.node = node; } + // Find the parts that are actually missing and not just blocked + // by tech or missions. + MissingParts = new List (); + for (int i = 0; i < info.UnavailableShipParts.Count; i++) { + string partName = info.UnavailableShipParts[i]; + if (PartLoader.getPartInfoByName (partName) == null) { + // UnavailableShipParts is already uniqued + MissingParts.Add (partName); + } + } info.description = info.description.Replace ('¨', '\n'); this.thumbPath = thumbPath; type = craftType; + this.isStock = isStock; } public class Dict : Dictionary { } diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index d3ca47aa..b12a1b42 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -87,10 +87,11 @@ public override void CreateUI () .ChildForceExpand (false,false) .Add (out craftThumb) .Add (out generateThumb) - .Text ("Generate") + .Image (SpriteLoader.GetSprite ("EL.Default.leftturn")) .OnClick (GenerateThumb) - .Anchor (AnchorPresets.StretchAll) - .SizeDelta (0, 0) + .Anchor (AnchorPresets.TopLeft) + .Pivot (PivotPresets.TopLeft) + .SizeDelta (24, 24) .Color (new UnityEngine.Color (0,0,0,0)) .Finish () .Finish () @@ -154,6 +155,7 @@ public override void CreateUI () relativePath = ""; craftThumb.Craft (""); + generateThumb.SetActive (false); craftItems = new ELCraftItem.List (craftGroup); craftItems.Content = craftList.Content; @@ -225,11 +227,13 @@ void UpdateCraftInfo () { if (selectedCraft != null) { craftThumb.Craft (selectedCraft.thumbPath); + generateThumb.SetActive (!selectedCraft.isStock && selectedCraft.canLoad); craftDescription.Text (selectedCraft.description); partEdit.interactable = true; } else { craftDescription.Text (""); craftThumb.Craft (""); + generateThumb.SetActive (false); partEdit.interactable = false; } } @@ -301,7 +305,7 @@ bool ScanDirectory (ELCraftType type, bool stock, string path) } else { tp = ELCraftThumb.UserPath (type, fp); } - craftItems.Add (new ELCraftItem (fp, mp, tp, type)); + craftItems.Add (new ELCraftItem (fp, mp, tp, type, stock)); } UIKit.UpdateListContent (craftItems); From 5545a2fd151e89acc1a7ecccf07561d8279da6ec Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 18:10:13 +0900 Subject: [PATCH 111/150] Display missing parts for applicable craft files --- Source/UI/CraftSelector.cs | 7 ++++++- Source/UI/Localization.cs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index b12a1b42..5fd50fbf 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with Extraplanetary Launchpads. If not, see . */ +using System; using System.IO; using UnityEngine.Events; using UnityEngine.UI; @@ -228,7 +229,11 @@ void UpdateCraftInfo () if (selectedCraft != null) { craftThumb.Craft (selectedCraft.thumbPath); generateThumb.SetActive (!selectedCraft.isStock && selectedCraft.canLoad); - craftDescription.Text (selectedCraft.description); + if (selectedCraft.canLoad) { + craftDescription.Text (selectedCraft.description); + } else { + craftDescription.Text (ELLocalization.MissingParts + "\n" + String.Join ("\n", selectedCraft.MissingParts)); + } partEdit.interactable = true; } else { craftDescription.Text (""); diff --git a/Source/UI/Localization.cs b/Source/UI/Localization.cs index 81238cc1..1675b55c 100644 --- a/Source/UI/Localization.cs +++ b/Source/UI/Localization.cs @@ -73,5 +73,6 @@ public static class ELLocalization public static string Save { get; } = "Save"; public static string SaveAndClose { get; } = "Save and Close"; public static string Close { get; } = "Close"; + public static string MissingParts { get; } = "Missing Parts:"; } } From 69038103252933cac683f2ad1bba4d3991bc57f7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 24 Oct 2020 22:55:15 +0900 Subject: [PATCH 112/150] Do up some sprites in anticipation of better tabs --- Assets/DefaultSkin.cfg | 35 +++++++++++++- Assets/Makefile | 12 +++++ Assets/ui_tabdesel.svg | 106 +++++++++++++++++++++++++++++++++++++++++ Assets/ui_tabempty.svg | 82 +++++++++++++++++++++++++++++++ Assets/ui_tabsel.svg | 106 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 340 insertions(+), 1 deletion(-) create mode 100644 Assets/ui_tabdesel.svg create mode 100644 Assets/ui_tabempty.svg create mode 100644 Assets/ui_tabsel.svg diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index 84eb67aa..5806dbd6 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -25,7 +25,7 @@ KodeUI_Skin { } Style { name = TabItemView - sprite = EL.Default.background + sprite = EL.Default.tabsel color = 0.25, 0.25, 0.25, 1 } Style { @@ -394,6 +394,39 @@ KodeUI_Sprite { border = 12, 12, 12, 12 } +KodeUI_Sprite { + name = EL.Default.tabdesel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.tabempty + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + +KodeUI_Sprite { + name = EL.Default.tabsel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + //defaults to full image: rect = 0, 0, , + //defaults to center of rect: pivot = 0.5, 0.5 + pixelsPerUnit = 100 + extrude = 1 + type = Tight + border = 8, 8, 8, 8 +} + KodeUI_Sprite { name = EL.Default.toggle_off textureUrl = ExtraplanetaryLaunchpads/UI/ui_toggle_off diff --git a/Assets/Makefile b/Assets/Makefile index 19ba30fd..ce21de5a 100644 --- a/Assets/Makefile +++ b/Assets/Makefile @@ -36,6 +36,9 @@ UI_IMAGES := \ ui_dropdown.png \ ui_leftturn.png \ ui_rightturn.png \ + ui_tabdesel.png \ + ui_tabempty.png \ + ui_tabsel.png \ ui_toggle_off.png \ ui_toggle_on.png \ $e @@ -108,6 +111,15 @@ ui_leftturn.png: ui_leftturn.svg ui_rightturn.png: ui_rightturn.svg inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ +ui_tabdesel.png: ui_tabdesel.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_tabempty.png: ui_tabempty.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + +ui_tabsel.png: ui_tabsel.svg + inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ + ui_toggle_off.png: ui_toggle_off.svg inkscape --export-width=24 --export-height=24 --export-type=png -o $@ $^ diff --git a/Assets/ui_tabdesel.svg b/Assets/ui_tabdesel.svg new file mode 100644 index 00000000..b8f46b71 --- /dev/null +++ b/Assets/ui_tabdesel.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_tabempty.svg b/Assets/ui_tabempty.svg new file mode 100644 index 00000000..9697edbe --- /dev/null +++ b/Assets/ui_tabempty.svg @@ -0,0 +1,82 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/Assets/ui_tabsel.svg b/Assets/ui_tabsel.svg new file mode 100644 index 00000000..9fb2e1cb --- /dev/null +++ b/Assets/ui_tabsel.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + From 27e5d190e3c3cb1cc99213a7879b4e83a60c95d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 25 Oct 2020 17:28:57 +0900 Subject: [PATCH 113/150] Fix some broken style setups --- Source/UI/PadLaunchpadView.cs | 1 + Source/UI/PadSurveyView.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Source/UI/PadLaunchpadView.cs b/Source/UI/PadLaunchpadView.cs index 87e8801b..79910afd 100644 --- a/Source/UI/PadLaunchpadView.cs +++ b/Source/UI/PadLaunchpadView.cs @@ -78,6 +78,7 @@ void RotateRight () public override void Style () { + base.Style (); } public void SetControl (ELBuildControl control) diff --git a/Source/UI/PadSurveyView.cs b/Source/UI/PadSurveyView.cs index 5158bc52..f159c83f 100644 --- a/Source/UI/PadSurveyView.cs +++ b/Source/UI/PadSurveyView.cs @@ -90,6 +90,7 @@ void RenameSite () public override void Style () { + base.Style (); } void ShowWanring () From 288f9b1ddf85f3d9079bcdb7f96ff981800546e1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 25 Oct 2020 18:53:19 +0900 Subject: [PATCH 114/150] Get tab margins working There will be more, but I'd messed up the submodule stuff earlier. --- Assets/DefaultSkin.cfg | 1 + KodeUI | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index 5806dbd6..585d3d3d 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -31,6 +31,7 @@ KodeUI_Skin { Style { name = TabItemView.Label color = 1, 1, 1, 1 + margin = 5, 5, 10, 10 } Style { name = LayoutPanel diff --git a/KodeUI b/KodeUI index 8855a7ad..c0edce16 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 8855a7adc227b93f1504afdbc3118e614a9a780b +Subproject commit c0edce16eb763193a25f931498571e34852a3b50 From 5ae396d576caef6cbd7711e321a142000ad25501 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 25 Oct 2020 19:31:02 +0900 Subject: [PATCH 115/150] Make the tab sprits differ --- Assets/DefaultSkin.cfg | 14 ++++++++++++-- KodeUI | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index 585d3d3d..942f068f 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -23,8 +23,18 @@ KodeUI_Skin { sprite = EL.Default.background color = 0.25, 0.25, 0.25, 1 } + Style { + name = TabController + sprite = EL.Default.tabempty + color = 0.25, 0.25, 0.25, 1 + } Style { name = TabItemView + sprite = EL.Default.tabdesel + color = 0.25, 0.25, 0.25, 1 + } + Style { + name = TabItemView.Selected sprite = EL.Default.tabsel color = 0.25, 0.25, 0.25, 1 } @@ -397,7 +407,7 @@ KodeUI_Sprite { KodeUI_Sprite { name = EL.Default.tabdesel - textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabdesel //defaults to full image: rect = 0, 0, , //defaults to center of rect: pivot = 0.5, 0.5 pixelsPerUnit = 100 @@ -408,7 +418,7 @@ KodeUI_Sprite { KodeUI_Sprite { name = EL.Default.tabempty - textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabsel + textureUrl = ExtraplanetaryLaunchpads/UI/ui_tabempty //defaults to full image: rect = 0, 0, , //defaults to center of rect: pivot = 0.5, 0.5 pixelsPerUnit = 100 diff --git a/KodeUI b/KodeUI index c0edce16..6ed2e2c5 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit c0edce16eb763193a25f931498571e34852a3b50 +Subproject commit 6ed2e2c5f8456a43dfab7fb5cea23067c703905f From f272ab2e4d644933bc27ee6974e5c429ebeece16 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 25 Oct 2020 20:09:13 +0900 Subject: [PATCH 116/150] Move part new/edit buttons to the browser This allows them to be enabled/disabled without changing the size of the browser window as they are now in the same row as the cancel/load buttons. --- Source/UI/CraftBrowser.cs | 33 ++++++++++++++++++++++++++++++++- Source/UI/CraftSelector.cs | 33 ++------------------------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/Source/UI/CraftBrowser.cs b/Source/UI/CraftBrowser.cs index 1f7bd38e..a8b7b27a 100644 --- a/Source/UI/CraftBrowser.cs +++ b/Source/UI/CraftBrowser.cs @@ -36,6 +36,9 @@ public class ELCraftBrowser : Window ELCraftTypeSelector typeSelector; ELCraftSelector craftSelector; UIButton loadButton; + Layout partButtons; + UIButton partNew; + UIButton partEdit; public override void CreateUI () { @@ -47,7 +50,7 @@ public override void CreateUI () .ChildForceExpand (false,false) .PreferredSizeFitter (true, true) .Anchor (AnchorPresets.MiddleCenter) - .Pivot (PivotPresets.TopLeft) + .Pivot (PivotPresets.MiddleCenter) .SetSkin ("EL.Default") .Add (out typeSelector) .OnSelectionChanged (CraftTypeSelected) @@ -68,6 +71,22 @@ public override void CreateUI () .Text (ELLocalization.Load) .OnClick (LoadSelection) .Finish () + .Add () + .FlexibleLayout (true, true) + .Finish () + .Add (out partButtons) + .Horizontal () + .ControlChildSize (true, true) + .ChildForceExpand (false,false) + .Add (out partNew) + .Text (ELLocalization.New) + .OnClick (CreatePart) + .Finish () + .Add (out partEdit) + .Text (ELLocalization.Edit) + .OnClick (EditPart) + .Finish () + .Finish () .Finish () .Add () .Text (ELVersionReport.GetVersion ()) @@ -97,6 +116,7 @@ void OnSelectionChanged (bool canLoad, bool doLoad) } else { loadButton.interactable = canLoad; } + partEdit.interactable = canLoad; } void CraftTypeSelected () @@ -104,6 +124,17 @@ void CraftTypeSelected () craftType = typeSelector.craftType; var stockCraft = typeSelector.stockCraft; craftSelector.SetCraftType (craftType, stockCraft); + partButtons.SetActive (craftType == ELCraftType.Part); + } + + void CreatePart () + { + ELPartEditorWindow.OpenEditor (null); + } + + void EditPart () + { + ELPartEditorWindow.OpenEditor (craftSelector.selectedCraft); } void SetDelegates (SelectFileCallback onFileSelected, diff --git a/Source/UI/CraftSelector.cs b/Source/UI/CraftSelector.cs index 5fd50fbf..31e59ef6 100644 --- a/Source/UI/CraftSelector.cs +++ b/Source/UI/CraftSelector.cs @@ -37,21 +37,18 @@ class CraftSelectionEvent : UnityEvent { } ScrollView craftList; ELCraftThumb craftThumb; - Layout partButtons; ScrollView craftInfo; UIText craftDescription; UIButton generateThumb; - UIButton partNew; - UIButton partEdit; ELCraftItem.List craftItems; ToggleGroup craftGroup; ELCraftItem _selectedCraft; - ELCraftItem selectedCraft + public ELCraftItem selectedCraft { get { return _selectedCraft; } - set { + private set { _selectedCraft = value; UpdateCraftInfo (); } @@ -96,19 +93,6 @@ public override void CreateUI () .Color (new UnityEngine.Color (0,0,0,0)) .Finish () .Finish () - .Add (out partButtons) - .Horizontal () - .ControlChildSize (true, true) - .ChildForceExpand (false,false) - .Add (out partNew) - .Text (ELLocalization.New) - .OnClick (CreatePart) - .Finish () - .Add (out partEdit) - .Text (ELLocalization.Edit) - .OnClick (EditPart) - .Finish () - .Finish () .Add (out craftInfo) .Horizontal (false) .Vertical (true) @@ -175,16 +159,6 @@ void GenerateThumb () selectedCraft.fullPath); } - void CreatePart () - { - ELPartEditorWindow.OpenEditor (null); - } - - void EditPart () - { - ELPartEditorWindow.OpenEditor (selectedCraft); - } - string relativePath; void pipelineSucceed (ConfigNode node, ELCraftItem craft) @@ -234,12 +208,10 @@ void UpdateCraftInfo () } else { craftDescription.Text (ELLocalization.MissingParts + "\n" + String.Join ("\n", selectedCraft.MissingParts)); } - partEdit.interactable = true; } else { craftDescription.Text (""); craftThumb.Craft (""); generateThumb.SetActive (false); - partEdit.interactable = false; } } @@ -254,7 +226,6 @@ public void SetCraftType (ELCraftType craftType, bool stock) { SetActive (true); SetRelativePath (craftType, stock, ""); - partButtons.SetActive (craftType == ELCraftType.Part); } void SetRelativePath (ELCraftType craftType, bool stock, string path) From bf907b1f5d048a88b67f695225ffe1f86739f8c3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 25 Oct 2020 20:19:12 +0900 Subject: [PATCH 117/150] Make ToggleText easier to click on --- KodeUI | 2 +- Source/UI/MiniToggle.cs | 8 +++++++- Source/UI/ToggleText.cs | 8 +++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/KodeUI b/KodeUI index 6ed2e2c5..6650e3e2 160000 --- a/KodeUI +++ b/KodeUI @@ -1 +1 @@ -Subproject commit 6ed2e2c5f8456a43dfab7fb5cea23067c703905f +Subproject commit 6650e3e2b38b9d4f95cdad2ff079fa378fc1baed diff --git a/Source/UI/MiniToggle.cs b/Source/UI/MiniToggle.cs index d9320da2..ab21cdfc 100644 --- a/Source/UI/MiniToggle.cs +++ b/Source/UI/MiniToggle.cs @@ -18,12 +18,13 @@ You should have received a copy of the GNU General Public License using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; +using UnityEngine.EventSystems; using KodeUI; namespace ExtraplanetaryLaunchpads { - public class MiniToggle : Layout + public class MiniToggle : Layout, IPointerClickHandler { UIToggle toggle; @@ -79,5 +80,10 @@ public MiniToggle SetIsOnWithoutNotify (bool on) toggle.SetIsOnWithoutNotify (on); return this; } + + public void OnPointerClick(PointerEventData eventData) + { + toggle.OnPointerClick (eventData); + } } } diff --git a/Source/UI/ToggleText.cs b/Source/UI/ToggleText.cs index 5ca4c019..38fe7695 100644 --- a/Source/UI/ToggleText.cs +++ b/Source/UI/ToggleText.cs @@ -18,13 +18,14 @@ You should have received a copy of the GNU General Public License using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; +using UnityEngine.EventSystems; using TMPro; using KodeUI; namespace ExtraplanetaryLaunchpads { - public class ToggleText : Layout + public class ToggleText : Layout, IPointerClickHandler { MiniToggle toggle; UIText label; @@ -78,5 +79,10 @@ public ToggleText SetIsOnWithoutNotify (bool on) toggle.SetIsOnWithoutNotify (on); return this; } + + public void OnPointerClick(PointerEventData eventData) + { + toggle.OnPointerClick (eventData); + } } } From c6d998e0540bab94fd924801bc4ad5064cf86728 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 29 Oct 2020 14:28:29 +0900 Subject: [PATCH 118/150] Tweak button margins --- Assets/DefaultSkin.cfg | 16 +++++++++++++--- Source/UI/BuildCraftView.cs | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Assets/DefaultSkin.cfg b/Assets/DefaultSkin.cfg index 942f068f..3fe2b006 100644 --- a/Assets/DefaultSkin.cfg +++ b/Assets/DefaultSkin.cfg @@ -41,7 +41,7 @@ KodeUI_Skin { Style { name = TabItemView.Label color = 1, 1, 1, 1 - margin = 5, 5, 10, 10 + margin = 5, 5, 4, 4 } Style { name = LayoutPanel @@ -53,6 +53,12 @@ KodeUI_Skin { sprite = EL.Default.button color = 0.5, 0.5, 0.5, 1 } + Style { + name = ButtonText + sprite = EL.Default.button + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 + } Style { name = UIDropdown sprite = EL.Default.background @@ -61,6 +67,7 @@ KodeUI_Skin { Style { name = UIDropdown.Label color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 } Style { name = UIDropdown.Arrow @@ -100,7 +107,8 @@ KodeUI_Skin { Style { name = UIDropdown.Item.ItemText sprite = EL.Default.background - color = 0.25, 0.25, 0.25, 1 + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 } Style { name = UIInputField @@ -238,6 +246,7 @@ KodeUI_Skin { name = PadSelector.Item.ItemText sprite = EL.Default.background color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 } Style { name = SiteSelector @@ -287,7 +296,8 @@ KodeUI_Skin { Style { name = SiteSelector.Item.ItemText sprite = EL.Default.background - color = 0.25, 0.25, 0.25, 1 + color = 1, 1, 1, 1 + margin = 5, 5, 4, 4 } Style { name = HighlightPad diff --git a/Source/UI/BuildCraftView.cs b/Source/UI/BuildCraftView.cs index 79b92cea..31c71560 100644 --- a/Source/UI/BuildCraftView.cs +++ b/Source/UI/BuildCraftView.cs @@ -137,7 +137,6 @@ public override void CreateUI() .Add (out selectFlagButton) .Image (flagTexture) .OnClick (SelectFlag) - .PreferredSize (48, 30) .Finish () .Add (out reloadButton) .Text (ELLocalization.Reload) @@ -231,7 +230,8 @@ public override void CreateUI() craftBoM.tmpText.overflowMode = TextOverflowModes.Linked; craftBoM.tmpText.linkedTextComponent = overflowText.tmpText; - selectFlagButton.ChildImage.AspectRatioSizeFitter (AspectRatioFitter.AspectMode.FitInParent, 1.6f); + selectFlagButton.Content.ChildAlignment (TextAnchor.MiddleCenter); + selectFlagButton.ChildImage.PreferredSize (48, 30); } void BuildCraft () From 6dcee32982f97a2defb08390294d42d2ff483375 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 30 Oct 2020 17:30:55 +0900 Subject: [PATCH 119/150] Create a fake editor to allow field editing of parts Right now, only the thumbnail generator uses it, but it seems to work, though crewed part lights come on (hmm....). --- Source/Editor/Editor.cs | 329 ++++++++++++++++++++++++++++++++++++++++ Source/Makefile | 1 + Source/UI/CraftThumb.cs | 63 ++++---- 3 files changed, 358 insertions(+), 35 deletions(-) create mode 100644 Source/Editor/Editor.cs diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs new file mode 100644 index 00000000..ef9d3376 --- /dev/null +++ b/Source/Editor/Editor.cs @@ -0,0 +1,329 @@ +/* +This file is part of Extraplanetary Launchpads. + +Extraplanetary Launchpads is free software: you can redistribute it and/or +modify it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Extraplanetary Launchpads is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Extraplanetary Launchpads. If not, see +. +*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using TMPro; + +namespace ExtraplanetaryLaunchpads { + + public class ELEditor : MonoBehaviour + { + const BindingFlags bindFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; + /** Delegate for Update and normal Start + */ + delegate void UpdateDelegate (); + /** Delegate for coroutine Start + */ + delegate IEnumerator StartDelegate (); + + static ELEditor editor; + + ShipConstruct ship; + + /** Disabled instance of the VAB/SPH editor so that part modules can + * get at \a ship when they need to. + */ + EditorLogic fakeEditor; + + List Updaters; + List FixedUpdaters; + List LateUpdaters; + // for Part.Start and any modules that use a coroutine Start + List CRStarters; + // For any other modules + List Starters; + + void Awake () + { + Updaters = new List (); + FixedUpdaters = new List (); + LateUpdaters = new List (); + CRStarters = new List (); + Starters = new List (); + + editor = this; + } + + void OnDestroy () + { + editor = null; + } + + void OnDisable () + { + Debug.Log ($"[ELEditor] OnDisable"); + + Updaters.Clear (); + FixedUpdaters.Clear (); + LateUpdaters.Clear (); + CRStarters.Clear (); + Starters.Clear (); + + // Remove the fake EditorLogic so it doesn't cause problems the + // next time the player goes to the VAB or SPH + if (fakeEditor) { + Destroy (fakeEditor.gameObject); + } + fakeEditor = null; + } + + /** Simple wrapper to create a delegate for update or normal Start + */ + UpdateDelegate CreateUpdateDelegate (MonoBehaviour module, MethodInfo method) + { + return (UpdateDelegate) Delegate.CreateDelegate (typeof (UpdateDelegate), module, method); + } + + /** Simple wrapper to create a delegate for coroutine Start + */ + StartDelegate CreateStartDelegate (MonoBehaviour module, MethodInfo method) + { + return (StartDelegate) Delegate.CreateDelegate (typeof (StartDelegate), module, method); + } + + /** Find the start method and add it to the appropriate list. + * + * Unity supports coroutine Start() (return IEnumerator instead of void) + * so need to check the return time. + */ + void FindStart (MonoBehaviour module) + { + var type = module.GetType (); + var start = type.GetMethod ("Start", bindFlags); + if (start == null) { + // many a PartModule relies on OnStart (called indirectly by + // Part.Start) rather than Start + return; + } + if (start.ReturnType == typeof(void)) { + // Strt is a normal (void) method + var del = CreateUpdateDelegate (module, start); + Starters.Add (del); + } else { + // Start is a coroutine + var del = CreateStartDelegate (module, start); + CRStarters.Add (del); + } + } + + /** Find the named update method and add a delegate to the list. + */ + void FindUpdater (MonoBehaviour module, string name, List updaters) + { + var type = module.GetType (); + var update = type.GetMethod (name, bindFlags); + if (update == null) { + // Not all modules implement all updaters (some don't impement + // any) + return; + } + var del = CreateUpdateDelegate (module, update); + updaters.Add (del); + } + + /** Run all the collected Start methods. + * + * Both Starters and CRStarters will be empty on completion. + */ + void RunStarters () + { + SetEditorScene (); + + // run through all the simple starters first + for (int i = Starters.Count; i-- > 0; ) { + try { + Starters[i] (); + } catch (Exception e) { + Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}"); + } + // These are one-shot methods, so remove as we go + Starters.RemoveAt (i); + } + + Debug.LogError ($"[ELEditor] RunStarters: running coroutine Start"); + // run through all the coroutine starters + var starters = new List (); + for (int i = 0; i < CRStarters.Count; i++) { + starters.Add (CRStarters[i] ()); + } + while (CRStarters.Count > 0) { + for (int i = CRStarters.Count; i-- > 0; ) { + bool remove = false; + try { + remove = !starters[i].MoveNext (); + } catch (Exception e) { + Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}"); + Debug.LogError ($" Disabling {starters[i]} ({CRStarters[i]})"); + remove = true; + } + if (remove) { + starters.RemoveAt (i); + CRStarters.RemoveAt (i); + } + } + } + Debug.LogError ($"[ELEditor] RunStarters: end coroutine Start"); + + RestoreScene (); + } + + void SetupEditor (ShipConstruct ship) + { + this.ship = ship; + + Debug.Log ($"[ELEditor] SetupEditor"); + + var go = new GameObject ("Fake Editor"); + go.transform.SetParent (transform, false); + + fakeEditor = go.AddComponent (); + // Do not want KSP's EditorLogic to run, it's needed only to hold + // ShipConstruct and any other necessary references so PartModules + // can run thinking they are in the editor. + fakeEditor.enabled = false; + + fakeEditor.ship = ship; + + var fnf = new GameObject ("FakeNameField", typeof (TMP_InputField)); + fnf.SetActive (false); + fakeEditor.shipNameField = fnf.GetComponent (); + + for (int i = 0; i < ship.parts.Count; i++) { + Part p = ship.parts[i]; + FindStart (p); + FindUpdater (p, "Update", Updaters); + FindUpdater (p, "FixedUpdate", FixedUpdaters); + FindUpdater (p, "LateUpdate", LateUpdaters); + for (int j = 0; j < p.Modules.Count; j++) { + PartModule m = p.Modules[j]; + FindStart (m); + FindUpdater (m, "Update", Updaters); + FindUpdater (m, "FixedUpdate", FixedUpdaters); + FindUpdater (m, "LateUpdate", LateUpdaters); + } + } + + RunStarters (); + } + + bool lsie; + bool lsif; + GameScenes scene; + + void SetEditorScene () + { + // Save true state in case this is ever used in a scene other than + // flight (though currently only editor is even vaguely expected) + lsie = HighLogic.LoadedSceneIsEditor; + lsif = HighLogic.LoadedSceneIsFlight; + scene = HighLogic.LoadedScene; + + // Trick the modules into thinking they are running in the editor + HighLogic.LoadedSceneIsEditor = true; + HighLogic.LoadedSceneIsFlight = false; + HighLogic.LoadedScene = GameScenes.EDITOR; + } + + void RestoreScene () + { + HighLogic.LoadedSceneIsEditor = lsie; + HighLogic.LoadedSceneIsFlight = lsif; + HighLogic.LoadedScene = scene; + } + + void RunUpdateDelegates (string updateType, List updaters) + { + SetEditorScene (); + + for (int i = updaters.Count; i-- > 0; ) { + try { + updaters[i] (); + } catch (Exception e) { + Debug.LogError ($"[ELEditor] caught {updateType} exception: {e.Message}"); + Debug.LogError ($" Disabling {updaters[i]}"); + updaters.RemoveAt (i); + } + } + + RestoreScene (); + } + + void Update () + { + RunUpdateDelegates ("Update", Updaters); + } + + void FixedUpdate () + { + RunUpdateDelegates ("FixedUpdate", FixedUpdaters); + } + + void LateUpdate () + { + RunUpdateDelegates ("LateUpdate", LateUpdaters); + } + + void SetActive (bool active) + { + gameObject.SetActive (active); + } + + /** Enable (create if necessary) the editor + * + * Disables all modules (including Part) and removes all colliders + * from the parts in ship. This means that Unity will not call Start + * or any of the update routines on the parts or their part modules. + */ + public static void EditShip (ShipConstruct ship) + { + // Disable the ship's parts and part modules so they won't run + // automatically + for (int i = ship.parts.Count; i-- > 0; ) { + Part p = ship.parts[i]; + p.enabled = false; + EL_Utils.DisableModules (p.gameObject); + EL_Utils.RemoveColliders (p.gameObject); + } + if (!editor) { + var go = new GameObject ("EL Editor"); + editor = go.AddComponent (); + } + editor.SetupEditor (ship); + editor.SetActive (true); + } + + /** Disable the editor and destroy the ship and its parts + */ + public static void ClearShip () + { + if (!editor) { + return; + } + if (editor.ship != null) { + for (int i = editor.ship.parts.Count; i-- > 0; ) { + Destroy (editor.ship.parts[i].gameObject); + } + } + editor.ship = null; + editor.SetActive (false); + } + } +} diff --git a/Source/Makefile b/Source/Makefile index 49bdd93a..e7758560 100644 --- a/Source/Makefile +++ b/Source/Makefile @@ -18,6 +18,7 @@ EL_FILES := \ Converter/KethaneResourceProvider.cs\ Converter/StockResourceProvider.cs \ DisposablePad/DisposablePad.cs \ + Editor/Editor.cs \ Hull/Box.cs \ Hull/Connectivity.cs \ Hull/CraftHull.cs \ diff --git a/Source/UI/CraftThumb.cs b/Source/UI/CraftThumb.cs index a7d4aac5..d773d2a1 100644 --- a/Source/UI/CraftThumb.cs +++ b/Source/UI/CraftThumb.cs @@ -119,38 +119,36 @@ static Texture2D takeSnapshot (ShipConstruct ship) return tex; } - static IEnumerator capture (ShipConstruct ship, string thumbPath, bool savedHL) + static IEnumerator capture (ShipConstruct ship, string thumbPath) { yield return null; + yield return null; + yield return null; + yield return null; + yield return null; - if (!thumbRig) { - // it died - yield break; - } + if (thumbRig) { + var tex = takeSnapshot (ship); + var png = tex.EncodeToPNG (); - var tex = takeSnapshot (ship); - var png = tex.EncodeToPNG (); + string dir = KSPUtil.ApplicationRootPath; + string path = dir + thumbPath; - string dir = KSPUtil.ApplicationRootPath; - string path = dir + thumbPath; + if (!ELCraftThumbManager.UpdateThumbCache (thumbPath, tex)) { + GameObject.Destroy (tex); + } - if (!ELCraftThumbManager.UpdateThumbCache (thumbPath, tex)) { - GameObject.Destroy (tex); - } + if (!Directory.Exists (dir)) { + Directory.CreateDirectory (dir); + } + File.WriteAllBytes (path, png); - if (!Directory.Exists (dir)) { - Directory.CreateDirectory (dir); + //Debug.Log ($"[ELCraftThumb] capture {path}"); + thumbRig.SetActive (false); } - File.WriteAllBytes (path, png); - - //Debug.Log ($"[ELCraftThumb] capture {path}"); - for (int i = ship.parts.Count; i-- > 0; ) { - GameObject.Destroy (ship.parts[i].gameObject); - } + ELEditor.ClearShip (); - HighLogic.LoadedSceneIsEditor = savedHL; - thumbRig.SetActive (false); } public static void Capture (ConfigNode craft, ELCraftType craftType, string craftFile) @@ -158,29 +156,24 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf var ship = new ShipConstruct (); ship.LoadShip (craft); - // Need to keep the parts around for a few frames, but - // various modules throw if things are not set up properly (which - // they won't be), but tricking the parts and their modules into - // thinking they're being placed in the editor fixes things - bool savedHL = HighLogic.LoadedSceneIsEditor; - HighLogic.LoadedSceneIsEditor = true; - if (ship.vesselDeltaV != null) { // The delta-v module is not needed. It has its own gameObject // for ShipConstruct. GameObject.Destroy (ship.vesselDeltaV.gameObject); ship.vesselDeltaV = null; } + // Need to keep the parts around for a few frames, but + // various modules throw if things are not set up properly (which + // they won't be), but tricking the parts and their modules into + // thinking they're being placed in the editor fixes things + ELEditor.EditShip (ship); for (int i = ship.parts.Count; i-- > 0; ) { - // See comment for HighLogic - ship.parts[i].ResumeState = PartStates.PLACEMENT; - ship.parts[i].State = PartStates.PLACEMENT; - // Make sure the part and main scene won't interact physcally // or graphically (thumbLayer is chosen to be a layer that is // not rendered by the scene cameras), and removing the // colliders ensures that the parts can't collide with anything - EL_Utils.RemoveColliders (ship.parts[i].gameObject); + // + // ELEditor removes the colliders EL_Utils.SetLightMasks (ship.parts[i].gameObject, thumbMask); EL_Utils.SetLayer (ship.parts[i].gameObject, thumbLayer, true); @@ -200,7 +193,7 @@ public static void Capture (ConfigNode craft, ELCraftType craftType, string craf // Need to wait a frame for the parts to be renderable // (don't know why, but my guess is to give the various renderers // a chance to set themselves up) - HighLogic.fetch.StartCoroutine (capture (ship, thumbPath, savedHL)); + HighLogic.fetch.StartCoroutine (capture (ship, thumbPath)); } public static string UserThumbName (ELCraftType craftType, string craftFile) From 6432293919e42315c0910a1eb150e2f25a64fa5d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 31 Oct 2020 09:57:11 +0900 Subject: [PATCH 120/150] Print delegate target and stack trace on exceptions Helps narrow down where errors occur. --- Source/Editor/Editor.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index ef9d3376..12b7cb17 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -153,12 +153,14 @@ void RunStarters () Starters[i] (); } catch (Exception e) { Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}"); + Debug.LogError ($"{e.StackTrace}"); + Debug.LogError ($" on {Starters[i].Target}"); } // These are one-shot methods, so remove as we go Starters.RemoveAt (i); } - Debug.LogError ($"[ELEditor] RunStarters: running coroutine Start"); + Debug.Log ($"[ELEditor] RunStarters: running coroutine Start"); // run through all the coroutine starters var starters = new List (); for (int i = 0; i < CRStarters.Count; i++) { @@ -171,6 +173,8 @@ void RunStarters () remove = !starters[i].MoveNext (); } catch (Exception e) { Debug.LogError ($"[ELEditor] caught Start exception: {e.Message}"); + Debug.LogError ($"{e.StackTrace}"); + Debug.LogError ($" on {Starters[i].Target}"); Debug.LogError ($" Disabling {starters[i]} ({CRStarters[i]})"); remove = true; } @@ -180,7 +184,7 @@ void RunStarters () } } } - Debug.LogError ($"[ELEditor] RunStarters: end coroutine Start"); + Debug.Log ($"[ELEditor] RunStarters: end coroutine Start"); RestoreScene (); } From 751652696463e713c852c1e10add04b7794bd918 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 31 Oct 2020 09:59:31 +0900 Subject: [PATCH 121/150] Set the editor root part This takes care of the exceptions in FAR, and probably many other mods. --- Source/Editor/Editor.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 12b7cb17..9784c8fc 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -35,6 +35,7 @@ public class ELEditor : MonoBehaviour delegate IEnumerator StartDelegate (); static ELEditor editor; + static FieldInfo rootPart; ShipConstruct ship; @@ -59,6 +60,7 @@ void Awake () CRStarters = new List (); Starters = new List (); + rootPart = typeof(EditorLogic).GetField ("rootPart", bindFlags); editor = this; } @@ -205,6 +207,8 @@ void SetupEditor (ShipConstruct ship) fakeEditor.enabled = false; fakeEditor.ship = ship; + Part root = ship.parts[0].localRoot; + rootPart.SetValue (fakeEditor, ship.parts[0].localRoot); var fnf = new GameObject ("FakeNameField", typeof (TMP_InputField)); fnf.SetActive (false); From e562cca31219d59737cde40b47966aaec2938699 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 31 Oct 2020 10:01:19 +0900 Subject: [PATCH 122/150] Delay starting parts and modules by a frame This lets EditorLogic set fetch before the modules try to access it. Seems to fix the error in cargo bays. --- Source/Editor/Editor.cs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 9784c8fc..4b3d81db 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -52,6 +52,8 @@ public class ELEditor : MonoBehaviour // For any other modules List Starters; + bool ready; + void Awake () { Updaters = new List (); @@ -79,6 +81,8 @@ void OnDisable () CRStarters.Clear (); Starters.Clear (); + ready = false; + // Remove the fake EditorLogic so it doesn't cause problems the // next time the player goes to the VAB or SPH if (fakeEditor) { @@ -189,6 +193,14 @@ void RunStarters () Debug.Log ($"[ELEditor] RunStarters: end coroutine Start"); RestoreScene (); + + ready = true; + } + + IEnumerator WaitAndRunStarters () + { + yield return null; + RunStarters (); } void SetupEditor (ShipConstruct ship) @@ -229,7 +241,7 @@ void SetupEditor (ShipConstruct ship) } } - RunStarters (); + StartCoroutine (WaitAndRunStarters ()); } bool lsie; @@ -276,17 +288,23 @@ void RunUpdateDelegates (string updateType, List updaters) void Update () { - RunUpdateDelegates ("Update", Updaters); + if (ready) { + RunUpdateDelegates ("Update", Updaters); + } } void FixedUpdate () { - RunUpdateDelegates ("FixedUpdate", FixedUpdaters); + if (ready) { + RunUpdateDelegates ("FixedUpdate", FixedUpdaters); + } } void LateUpdate () { - RunUpdateDelegates ("LateUpdate", LateUpdaters); + if (ready) { + RunUpdateDelegates ("LateUpdate", LateUpdaters); + } } void SetActive (bool active) @@ -314,8 +332,8 @@ public static void EditShip (ShipConstruct ship) var go = new GameObject ("EL Editor"); editor = go.AddComponent (); } - editor.SetupEditor (ship); editor.SetActive (true); + editor.SetupEditor (ship); } /** Disable the editor and destroy the ship and its parts From fe35addd7afcc483a5c827110d9fe209ff2bffee Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 31 Oct 2020 11:35:52 +0900 Subject: [PATCH 123/150] Add extra logging for updaters, too Not that I've seen anything yet, but... --- Source/Editor/Editor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index 4b3d81db..a627a75e 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -278,6 +278,8 @@ void RunUpdateDelegates (string updateType, List updaters) updaters[i] (); } catch (Exception e) { Debug.LogError ($"[ELEditor] caught {updateType} exception: {e.Message}"); + Debug.LogError ($"{e.StackTrace}"); + Debug.LogError ($" on {updaters[i].Target}"); Debug.LogError ($" Disabling {updaters[i]}"); updaters.RemoveAt (i); } From 6b1cd7d1fffd979d70598358fad58f15d9dccca7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 31 Oct 2020 13:58:20 +0900 Subject: [PATCH 124/150] Prevent NRE's in EditorLogic.UpdateUI Ugh. --- Source/Editor/Editor.cs | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index a627a75e..56911599 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -20,6 +20,7 @@ You should have received a copy of the GNU General Public License using System.Collections.Generic; using System.Reflection; using UnityEngine; +using UnityEngine.UI; using TMPro; namespace ExtraplanetaryLaunchpads { @@ -222,9 +223,37 @@ void SetupEditor (ShipConstruct ship) Part root = ship.parts[0].localRoot; rootPart.SetValue (fakeEditor, ship.parts[0].localRoot); - var fnf = new GameObject ("FakeNameField", typeof (TMP_InputField)); - fnf.SetActive (false); - fakeEditor.shipNameField = fnf.GetComponent (); + var nfo = new GameObject ("FakeNameField", typeof (TMP_InputField)); + nfo.transform.SetParent (go.transform, false); + nfo.SetActive (false); + var fnf = nfo.GetComponent (); + fakeEditor.shipNameField = fnf; + fakeEditor.shipDescriptionField = fnf; + + var bo = new GameObject ("FakeButton", + typeof (Button), + typeof (FlagBrowserButton), + typeof (KSP.UI.UIOnClick)); + bo.transform.SetParent (go.transform, false); + bo.SetActive (false); + var fb = bo.GetComponent