diff --git a/GameData/ConformalDecals/Plugins/ConformalDecals.dll b/GameData/ConformalDecals/Plugins/ConformalDecals.dll
index 76afae2..f6320b6 100644
Binary files a/GameData/ConformalDecals/Plugins/ConformalDecals.dll and b/GameData/ConformalDecals/Plugins/ConformalDecals.dll differ
diff --git a/GameData/ConformalDecals/Resources/ConformalDecals.cfg b/GameData/ConformalDecals/Resources/ConformalDecals.cfg
index bed0e9c..4a8e3e6 100644
--- a/GameData/ConformalDecals/Resources/ConformalDecals.cfg
+++ b/GameData/ConformalDecals/Resources/ConformalDecals.cfg
@@ -20,4 +20,39 @@ CONFORMALDECALS {
shader = KSP/Specular (Transparent)
shader = Solid Color (Alpha)
}
+
+ FONT {
+ name = LiberationSans SDF
+ title = Liberation Sans
+ }
+
+ FONT {
+ name = Calibri SDF
+ title = Calibri
+ }
+
+ FONT {
+ name = NotoSans-Regular SDF
+ title = Noto Sans
+ }
+
+ FONT {
+ name = Dited SDF
+ title = Dited
+ }
+
+ FONT {
+ name = Waukegan LDO Extended SDF
+ title = Waukegan Extended
+ }
+
+ FONT {
+ name = Nasalization SDF
+ title = Nasalization
+ }
+
+ FONT {
+ name = Helvetica SDF
+ title = Helvetica
+ }
}
\ No newline at end of file
diff --git a/GameData/ConformalDecals/Resources/conformaldecals.kspfont b/GameData/ConformalDecals/Resources/conformaldecals.kspfont
index 94dc394..efe7dea 100644
--- a/GameData/ConformalDecals/Resources/conformaldecals.kspfont
+++ b/GameData/ConformalDecals/Resources/conformaldecals.kspfont
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c543a58c9bc1ea96e26ce85625ca1fd765f5f1067f0eeca8fbdf68a2fe7e66ab
-size 139184
+oid sha256:29f1da73b9f5fbd996162fb61f99378b5f05fbc35d93d04907c6025963f8a4c4
+size 347881
diff --git a/GameData/ConformalDecals/Resources/ui.conformaldecals b/GameData/ConformalDecals/Resources/ui.conformaldecals
index c8c8f29..c5bf6db 100644
Binary files a/GameData/ConformalDecals/Resources/ui.conformaldecals and b/GameData/ConformalDecals/Resources/ui.conformaldecals differ
diff --git a/Source/ConformalDecals/ConformalDecals.csproj b/Source/ConformalDecals/ConformalDecals.csproj
index 2c7ba10..29fc765 100644
--- a/Source/ConformalDecals/ConformalDecals.csproj
+++ b/Source/ConformalDecals/ConformalDecals.csproj
@@ -30,7 +30,7 @@
prompt
4
bin\Release\ConformalDecals.xml
- CS1591
+ CS1591,CS0649
@@ -83,10 +83,13 @@
+
-
+
+
+
diff --git a/Source/ConformalDecals/DecalConfig.cs b/Source/ConformalDecals/DecalConfig.cs
index 40d2789..d019383 100644
--- a/Source/ConformalDecals/DecalConfig.cs
+++ b/Source/ConformalDecals/DecalConfig.cs
@@ -1,13 +1,17 @@
using System.Collections.Generic;
+using ConformalDecals.Text;
using ConformalDecals.Util;
+using TMPro;
+using UniLinq;
using UnityEngine;
namespace ConformalDecals {
public static class DecalConfig {
- private static Texture2D _blankNormal;
- private static List _shaderBlacklist;
- private static int _decalLayer = 31;
- private static bool _selectableInFlight;
+ private static Texture2D _blankNormal;
+ private static List _shaderBlacklist;
+ private static Dictionary _fontList;
+ private static int _decalLayer = 31;
+ private static bool _selectableInFlight;
private struct LegacyShaderEntry {
public string name;
@@ -37,12 +41,17 @@ namespace ConformalDecals {
},
};
+
public static Texture2D BlankNormal => _blankNormal;
public static int DecalLayer => _decalLayer;
public static bool SelectableInFlight => _selectableInFlight;
+ public static IEnumerable Fonts => _fontList.Values;
+
+ public static DecalFont FallbackFont { get; private set; }
+
public static bool IsBlacklisted(Shader shader) {
return IsBlacklisted(shader.name);
}
@@ -63,14 +72,40 @@ namespace ConformalDecals {
return false;
}
+ public static DecalFont GetFont(string name) {
+ if (_fontList.TryGetValue(name, out var font)) {
+ return font;
+ }
+ else {
+ throw new KeyNotFoundException($"Font {name} not found");
+ }
+ }
+
private static void ParseConfig(ConfigNode node) {
+
+ ParseUtil.ParseIntIndirect(ref _decalLayer, node, "decalLayer");
+ ParseUtil.ParseBoolIndirect(ref _selectableInFlight, node, "selectableInFlight");
+
foreach (var blacklist in node.GetNodes("SHADERBLACKLIST")) {
foreach (var shaderName in blacklist.GetValuesList("shader")) {
_shaderBlacklist.Add(shaderName);
}
-
- ParseUtil.ParseIntIndirect(ref _decalLayer, node, "decalLayer");
- ParseUtil.ParseBoolIndirect(ref _selectableInFlight, node, "selectableInFlight");
+ }
+
+ var allFonts = Resources.FindObjectsOfTypeAll();
+
+ foreach (var fontNode in node.GetNodes("FONT")) {
+ var name = ParseUtil.ParseString(fontNode, "name");
+ var title = ParseUtil.ParseString(fontNode, "title", true, name);
+ var style = ParseUtil.ParseInt(fontNode, "style", true);
+
+ var font = allFonts.First(o => o.name == name);
+ if (font == null) {
+ Debug.LogWarning($"[ConformalDecals] Could not found named {name}");
+ }
+
+ Debug.Log($"Adding font named {name}");
+ _fontList.Add(name, new DecalFont(title, font, (FontStyles) style));
}
}
@@ -96,6 +131,7 @@ namespace ConformalDecals {
// ReSharper disable once UnusedMember.Global
public static void ModuleManagerPostLoad() {
_shaderBlacklist = new List();
+ _fontList = new Dictionary();
var configs = GameDatabase.Instance.GetConfigs("CONFORMALDECALS");
diff --git a/Source/ConformalDecals/ModuleConformalText.cs b/Source/ConformalDecals/ModuleConformalText.cs
index 6957e51..93c6e19 100644
--- a/Source/ConformalDecals/ModuleConformalText.cs
+++ b/Source/ConformalDecals/ModuleConformalText.cs
@@ -1,33 +1,52 @@
+using System;
using ConformalDecals.Text;
using ConformalDecals.UI;
using ConformalDecals.Util;
using TMPro;
using UnityEngine;
-using UnityEngine.UI;
namespace ConformalDecals {
- public class ModuleConformalText: ModuleConformalDecal {
+ public class ModuleConformalText : ModuleConformalDecal {
[KSPField(isPersistant = true)] public string text = "Hello World!";
+ [KSPField(isPersistant = true)] public string font = "Calibri SDF";
+ [KSPField(isPersistant = true)] public int style;
+ [KSPField(isPersistant = true)] public bool vertical;
+ [KSPField(isPersistant = true)] public Color color = Color.black;
+ [KSPField(isPersistant = true)] public Color outlineColor = Color.white;
+ [KSPField(isPersistant = true)] public float outlineWidth;
- private GameObject _textEntryGui;
+ private DecalText _text;
+
+ private TextEntryController _textEntryController;
public override void OnLoad(ConfigNode node) {
base.OnLoad(node);
-
}
public override void OnStart(StartState state) {
base.OnStart(state);
+ var decalFont = DecalConfig.GetFont(font);
+
+ _text = new DecalText {
+ text = text,
+ font = decalFont,
+ style = (FontStyles) style,
+ vertical = vertical,
+ color = color,
+ outlineColor = outlineColor,
+ outlineWidth = outlineWidth
+ };
+ }
+
+ public void OnTextUpdate(DecalText newText) {
+ _text = newText;
}
[KSPEvent(guiActive = false, guiActiveEditor = true, guiName = "#LOC_ConformalDecals_gui-select-flag")]
- public void SetText()
- {
- if (_textEntryGui == null) {
- _textEntryGui = Instantiate(UILoader.textEntryPrefab, MainCanvasUtil.MainCanvas.transform, true);
- //_textEntryGui.AddComponent();
- //MenuNavigation.SpawnMenuNavigation(_textEntryGui, Navigation.Mode.Automatic, true);
+ public void SetText() {
+ if (_textEntryController == null) {
+ _textEntryController = TextEntryController.Create(_text, OnTextUpdate);
}
}
}
diff --git a/Source/ConformalDecals/Text/DecalFont.cs b/Source/ConformalDecals/Text/DecalFont.cs
new file mode 100644
index 0000000..936a44b
--- /dev/null
+++ b/Source/ConformalDecals/Text/DecalFont.cs
@@ -0,0 +1,27 @@
+using System;
+using TMPro;
+
+namespace ConformalDecals.Text {
+ public class DecalFont {
+ public readonly string title;
+ public readonly TMP_FontAsset fontAsset;
+ public readonly FontStyles fontStyle;
+
+ public DecalFont(string title, TMP_FontAsset fontAsset, FontStyles fontStyle) {
+ if (fontAsset == null) throw new ArgumentNullException(nameof(fontAsset));
+
+ this.title = title;
+ this.fontAsset = fontAsset;
+ this.fontStyle = fontStyle;
+ }
+
+ public void SetupSample(TMP_Text tmp) {
+ if (tmp == null) throw new ArgumentNullException(nameof(tmp));
+ if (fontAsset == null) throw new InvalidOperationException("DecalFont has not been initialized and Font is null.");
+
+ tmp.text = title;
+ tmp.font = fontAsset;
+ tmp.fontStyle = fontStyle;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ConformalDecals/Text/DecalText.cs b/Source/ConformalDecals/Text/DecalText.cs
new file mode 100644
index 0000000..aa59d21
--- /dev/null
+++ b/Source/ConformalDecals/Text/DecalText.cs
@@ -0,0 +1,16 @@
+using System;
+using TMPro;
+using UnityEngine;
+
+namespace ConformalDecals.Text {
+ public struct DecalText {
+ public string text;
+ public DecalFont font;
+ public FontStyles style;
+ public bool vertical;
+
+ public Color color;
+ public Color outlineColor;
+ public float outlineWidth;
+ }
+}
\ No newline at end of file
diff --git a/Source/ConformalDecals/Text/FormattedText.cs b/Source/ConformalDecals/Text/FormattedText.cs
deleted file mode 100644
index e69ab2c..0000000
--- a/Source/ConformalDecals/Text/FormattedText.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using TMPro;
-using UnityEngine;
-
-namespace ConformalDecals.Text {
- public struct FormattedText {
- public string text;
- public TMP_FontAsset font;
- public FontStyles style;
- public bool vertical;
-
- public Color32 color;
- public Color32 outlineColor;
- public float outlineWidth;
- }
-}
\ No newline at end of file
diff --git a/Source/ConformalDecals/UI/FontMenuController.cs b/Source/ConformalDecals/UI/FontMenuController.cs
new file mode 100644
index 0000000..5b28139
--- /dev/null
+++ b/Source/ConformalDecals/UI/FontMenuController.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using ConformalDecals.Text;
+using UniLinq;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace ConformalDecals.UI {
+ public class FontMenuController : MonoBehaviour {
+ [SerializeField] private GameObject _menuItem;
+ [SerializeField] private GameObject _menuList;
+
+ public DecalFont currentFont;
+
+ public delegate void FontUpdateReceiver(DecalFont font);
+
+ public FontUpdateReceiver fontUpdateCallback;
+
+ public static FontMenuController Create(IEnumerable fonts, DecalFont currentFont, FontUpdateReceiver fontUpdateCallback) {
+ var menu = Instantiate(UILoader.FontMenuPrefab, MainCanvasUtil.MainCanvas.transform, true);
+ menu.AddComponent();
+ MenuNavigation.SpawnMenuNavigation(menu, Navigation.Mode.Automatic, true);
+
+ var controller = menu.GetComponent();
+ controller.fontUpdateCallback = fontUpdateCallback;
+ controller.currentFont = currentFont;
+ controller.Populate(fonts);
+ return controller;
+ }
+
+ public void OnClose() {
+ Destroy(gameObject);
+ }
+
+ public void OnFontSelected(DecalFont font) {
+ currentFont = font ?? throw new ArgumentNullException(nameof(font));
+ fontUpdateCallback(currentFont);
+ }
+
+ public void Populate(IEnumerable fonts) {
+ if (fonts == null) throw new ArgumentNullException(nameof(fonts));
+
+ Toggle active = null;
+
+ foreach (var font in fonts.OrderBy(x => x.title)) {
+ Debug.Log(font.title);
+ var listItem = GameObject.Instantiate(_menuItem, _menuList.transform);
+ listItem.name = font.title;
+ listItem.SetActive(true);
+
+ var fontItem = listItem.AddComponent();
+ fontItem.Font = font;
+ fontItem.fontSelectionCallback = OnFontSelected;
+
+ if (font == currentFont) active = fontItem.toggle;
+ }
+
+ if (active != null) active.isOn = true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ConformalDecals/UI/FontMenuItem.cs b/Source/ConformalDecals/UI/FontMenuItem.cs
new file mode 100644
index 0000000..8d9bc74
--- /dev/null
+++ b/Source/ConformalDecals/UI/FontMenuItem.cs
@@ -0,0 +1,36 @@
+using System;
+using ConformalDecals.Text;
+using TMPro;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace ConformalDecals.UI {
+ public class FontMenuItem : MonoBehaviour {
+ public DecalFont Font {
+ get => _font;
+ set {
+ _font = value;
+ _font.SetupSample(_label);
+ }
+ }
+
+ public delegate void FontSelectionReceiver(DecalFont font);
+
+ public FontSelectionReceiver fontSelectionCallback;
+ public Toggle toggle;
+
+ private DecalFont _font;
+ private TMP_Text _label;
+
+ private void Awake() {
+ _label = gameObject.GetComponentInChildren();
+ toggle = gameObject.GetComponent();
+ toggle.isOn = false;
+ toggle.onValueChanged.AddListener(delegate { OnToggle(toggle); });
+ }
+
+ public void OnToggle(Toggle change) {
+ if (change.isOn) fontSelectionCallback?.Invoke(_font);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ConformalDecals/UI/TextEntryController.cs b/Source/ConformalDecals/UI/TextEntryController.cs
index 115e4c8..fbc5436 100644
--- a/Source/ConformalDecals/UI/TextEntryController.cs
+++ b/Source/ConformalDecals/UI/TextEntryController.cs
@@ -1,4 +1,3 @@
-using System;
using ConformalDecals.Text;
using TMPro;
using UnityEngine;
@@ -6,12 +5,15 @@ using UnityEngine.UI;
namespace ConformalDecals.UI {
public class TextEntryController : MonoBehaviour {
- private FormattedText _text;
+ public delegate void TextUpdateReceiver(DecalText text);
+
+ public TextUpdateReceiver textUpdateCallback;
+
+ public DecalText decalText;
+ private FontMenuController _fontMenu;
[SerializeField] private Selectable _textBox;
- [SerializeField] private Toggle _fontColorButton;
- [SerializeField] private Toggle _fontButton;
- [SerializeField] private Toggle _outlineColorButton;
+ [SerializeField] private Button _fontButton;
[SerializeField] private Slider _outlineWidthSlider;
[SerializeField] private Toggle _boldButton;
@@ -20,89 +22,123 @@ namespace ConformalDecals.UI {
[SerializeField] private Toggle _smallCapsButton;
[SerializeField] private Toggle _verticalButton;
- public delegate void TextUpdateReceiver(FormattedText text);
+ public static TextEntryController Create(DecalText text, TextUpdateReceiver textUpdateCallback) {
+ var window = Instantiate(UILoader.TextEntryPrefab, MainCanvasUtil.MainCanvas.transform, true);
+ window.AddComponent();
+ MenuNavigation.SpawnMenuNavigation(window, Navigation.Mode.Automatic, true);
- public delegate void TextCancelReceiver();
+ var controller = window.GetComponent();
+ controller.decalText = text;
+ controller.textUpdateCallback = textUpdateCallback;
+ text.font.SetupSample(controller._fontButton.GetComponentInChildren());
- public TextUpdateReceiver textUpdateCallback;
- public TextCancelReceiver textCancelCallback;
+ return controller;
+ }
private void Start() {
- (_textBox as TMP_InputField).text = _text.text;
+ ((TMP_InputField) _textBox).text = decalText.text;
+
+ _outlineWidthSlider.value = decalText.outlineWidth;
+ _boldButton.isOn = (decalText.style & FontStyles.Bold) != 0;
+ _italicButton.isOn = (decalText.style & FontStyles.Italic) != 0;
+ _underlineButton.isOn = (decalText.style & FontStyles.Underline) != 0;
+ _smallCapsButton.isOn = (decalText.style & FontStyles.SmallCaps) != 0;
+ _verticalButton.isOn = decalText.vertical;
- _boldButton.isOn = (_text.style | FontStyles.Bold) != 0;
- _italicButton.isOn = (_text.style | FontStyles.Italic) != 0;
- _underlineButton.isOn = (_text.style | FontStyles.Underline) != 0;
- _smallCapsButton.isOn = (_text.style | FontStyles.SmallCaps) != 0;
- _verticalButton.isOn = _text.vertical;
}
- public void Close() {
+ public void OnClose() {
+ if (_fontMenu != null) _fontMenu.OnClose();
Destroy(gameObject);
}
- public void OnCancel() {
- textCancelCallback();
- Close();
+ public void OnAnyUpdate() {
+ textUpdateCallback(decalText);
}
- public void OnApply() {
- textUpdateCallback(_text);
- Close();
+ public void OnTextUpdate(string newText) {
+ this.decalText.text = newText;
+
+ OnAnyUpdate();
}
- public void OnTextUpdate(string text) {
- _text.text = text;
- textUpdateCallback(_text);
+ public void OnFontMenu() {
+ if (_fontMenu == null) _fontMenu = FontMenuController.Create(DecalConfig.Fonts, decalText.font, OnFontUpdate);
+ }
+
+ public void OnFontUpdate(DecalFont font) {
+ decalText.font = font;
+ font.SetupSample(_fontButton.GetComponentInChildren());
+
+ var textBox = ((TMP_InputField) _textBox);
+ textBox.textComponent.fontStyle = decalText.style | decalText.font.fontStyle;
+ textBox.fontAsset = decalText.font.fontAsset;
+ OnAnyUpdate();
}
- public void OnFontMenu(bool state) { }
- public void OnColorMenu(bool state) { }
+ public void OnColorMenu() { }
- public void OnOutlineColorMenu(bool state) { }
+ public void OnColorUpdate(Color color) {
+ decalText.color = color;
+ OnAnyUpdate();
+ }
- public void OnOutlineUpdate(float value) {
- _text.outlineWidth = value;
- textUpdateCallback(_text);
+ public void OnOutlineColorMenu() { }
+ public void OnOutlineColorUpdate(Color color) {
+ decalText.outlineColor = color;
+ OnAnyUpdate();
+ }
+
+ public void OnOutlineUpdate(float value) {
+ decalText.outlineWidth = value;
+ OnAnyUpdate();
}
public void OnBoldUpdate(bool state) {
- if (state) _text.style |= FontStyles.Bold;
- else _text.style &= ~FontStyles.Bold;
+ if (state) decalText.style |= FontStyles.Bold;
+ else decalText.style &= ~FontStyles.Bold;
- textUpdateCallback(_text);
+ ((TMP_InputField) _textBox).textComponent.fontStyle = decalText.style | decalText.font.fontStyle;
+
+ OnAnyUpdate();
}
public void OnItalicUpdate(bool state) {
- if (state) _text.style |= FontStyles.Italic;
- else _text.style &= ~FontStyles.Italic;
+ if (state) decalText.style |= FontStyles.Italic;
+ else decalText.style &= ~FontStyles.Italic;
+
+ ((TMP_InputField) _textBox).textComponent.fontStyle = decalText.style | decalText.font.fontStyle;
- textUpdateCallback(_text);
+ OnAnyUpdate();
}
public void OnUnderlineUpdate(bool state) {
- if (state) _text.style |= FontStyles.Underline;
- else _text.style &= ~FontStyles.Underline;
+ if (state) decalText.style |= FontStyles.Underline;
+ else decalText.style &= ~FontStyles.Underline;
- textUpdateCallback(_text);
+ ((TMP_InputField) _textBox).textComponent.fontStyle = decalText.style | decalText.font.fontStyle;
+
+ OnAnyUpdate();
}
public void OnSmallCapsUpdate(bool state) {
- if (state) _text.style |= FontStyles.SmallCaps;
- else _text.style &= ~FontStyles.SmallCaps;
+ if (state) decalText.style |= FontStyles.SmallCaps;
+ else decalText.style &= ~FontStyles.SmallCaps;
+
+ ((TMP_InputField) _textBox).textComponent.fontStyle = decalText.style | decalText.font.fontStyle;
- textUpdateCallback(_text);
+ OnAnyUpdate();
}
public void OnVerticalUpdate(bool state) {
- _text.vertical = state;
- textUpdateCallback(_text);
+ decalText.vertical = state;
+ OnAnyUpdate();
}
}
}
\ No newline at end of file
diff --git a/Source/ConformalDecals/UI/UILoader.cs b/Source/ConformalDecals/UI/UILoader.cs
index aa6fb8c..8c7f876 100644
--- a/Source/ConformalDecals/UI/UILoader.cs
+++ b/Source/ConformalDecals/UI/UILoader.cs
@@ -8,30 +8,22 @@ namespace ConformalDecals.UI {
public class UILoader : MonoBehaviour {
private static readonly string Path = KSPUtil.ApplicationRootPath + "GameData/ConformalDecals/Resources/";
- public static GameObject textEntryPrefab;
+ private static GameObject _textEntryPrefab;
+ private static GameObject _fontMenuPrefab;
+
+ public static GameObject FontMenuPrefab => _fontMenuPrefab;
+ public static GameObject TextEntryPrefab => _textEntryPrefab;
private void Awake() {
var prefabs = AssetBundle.LoadFromFile(Path + "ui.conformaldecals");
- textEntryPrefab = prefabs.LoadAsset("TextEntryPanel") as GameObject;
-
- ProcessWindow(textEntryPrefab);
-
- Debug.Log("[ConformalDecals] UI prefabs loaded and modified");
- Debug.Log($"[ConformalDecals] {MainCanvasUtil.MainCanvas.renderMode}");
- Debug.Log($"[ConformalDecals] {MainCanvasUtil.MainCanvas.sortingOrder}");
- Debug.Log($"[ConformalDecals] {MainCanvasUtil.MainCanvas.sortingLayerID}");
- Debug.Log($"[ConformalDecals] {MainCanvasUtil.MainCanvas.sortingLayerName}");
- foreach (var layer in SortingLayer.layers) {
- Debug.Log(layer.name);
- Debug.Log(layer.id);
- Debug.Log(layer.value);
- }
-
+ _textEntryPrefab = prefabs.LoadAsset("TextEntryPanel") as GameObject;
+ _fontMenuPrefab = prefabs.LoadAsset("FontMenuPanel") as GameObject;
- var window = Instantiate(UILoader.textEntryPrefab, MainCanvasUtil.MainCanvas.transform, true);
+ ProcessWindow(_textEntryPrefab);
+ ProcessWindow(_fontMenuPrefab);
}
-
+
private static void ProcessWindow(GameObject window) {
var skin = UISkinManager.defaultSkin;
var font = UISkinManager.TMPFont;