diff --git a/src/CSConsole/ConsoleController.cs b/src/CSConsole/ConsoleController.cs index 43953d0..d8ba4a6 100644 --- a/src/CSConsole/ConsoleController.cs +++ b/src/CSConsole/ConsoleController.cs @@ -603,7 +603,7 @@ If the game was built with Unity's stubbed netstandard 2.0 runtime, you can fix } } - private static readonly Dictionary helpDict = new Dictionary(); + private static readonly Dictionary helpDict = new(); public static void SetupHelpInteraction() { @@ -658,15 +658,17 @@ var x = 5; ++x; /* The following helpers are available in REPL mode: - * GetUsing(); - prints the current using directives to the console log - * GetVars(); - prints the names and values of the REPL variables you have defined - * GetClasses(); - prints the names and members of the classes you have defined - * Log(obj); - prints a message to the console log * CurrentTarget; - System.Object, the target of the active Inspector tab * AllTargets; - System.Object[], the targets of all Inspector tabs + * Log(obj); - prints a message to the console log * Inspect(obj); - inspect the object with the Inspector * Inspect(someType); - inspect a Type with static reflection * Start(enumerator); - starts the IEnumerator as a Coroutine + * Copy(obj); - copies the object to the UnityExplorer Clipboard + * Paste(); - System.Object, the contents of the Clipboard. + * GetUsing(); - prints the current using directives to the console log + * GetVars(); - prints the names and values of the REPL variables you have defined + * GetClasses(); - prints the names and members of the classes you have defined * help; - the default REPL help command, contains additional helpers. */"; diff --git a/src/CSConsole/ScriptInteraction.cs b/src/CSConsole/ScriptInteraction.cs index 2352188..68d0ed7 100644 --- a/src/CSConsole/ScriptInteraction.cs +++ b/src/CSConsole/ScriptInteraction.cs @@ -6,40 +6,39 @@ using System.Linq; using System.Text; using UnityEngine; using UnityExplorer.Runtime; +using UnityExplorer.UI.Panels; using UniverseLib; namespace UnityExplorer.CSConsole { public class ScriptInteraction : InteractiveBase { + public static object CurrentTarget + => InspectorManager.ActiveInspector?.Target; + + public static object[] AllTargets + => InspectorManager.Inspectors.Select(it => it.Target).ToArray(); + public static void Log(object message) - { - ExplorerCore.Log(message); - } - - public static object CurrentTarget => InspectorManager.ActiveInspector?.Target; - - public static object[] AllTargets => InspectorManager.Inspectors.Select(it => it.Target).ToArray(); + => ExplorerCore.Log(message); public static void Inspect(object obj) - { - InspectorManager.Inspect(obj); - } + => InspectorManager.Inspect(obj); public static void Inspect(Type type) - { - InspectorManager.Inspect(type); - } + => InspectorManager.Inspect(type); - public static void Start(IEnumerator ienumerator) - { - RuntimeProvider.Instance.StartCoroutine(ienumerator); - } + public static void Start(IEnumerator ienumerator) + => RuntimeProvider.Instance.StartCoroutine(ienumerator); + + public static void Copy(object obj) + => ClipboardPanel.Copy(obj); + + public static object Paste() + => ClipboardPanel.Current; public static void GetUsing() - { - Log(Evaluator.GetUsing()); - } + => Log(Evaluator.GetUsing()); public static void GetVars() { diff --git a/src/CacheObject/CacheConfigEntry.cs b/src/CacheObject/CacheConfigEntry.cs index 84f59d1..a5a93cf 100644 --- a/src/CacheObject/CacheConfigEntry.cs +++ b/src/CacheObject/CacheConfigEntry.cs @@ -44,6 +44,6 @@ namespace UnityExplorer.CacheObject RefConfigElement.BoxedValue = value; } - protected override bool SetCellEvaluateState(CacheObjectCell cell) => false; + protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; } } diff --git a/src/CacheObject/CacheKeyValuePair.cs b/src/CacheObject/CacheKeyValuePair.cs index 1a3dd9d..bccdcdc 100644 --- a/src/CacheObject/CacheKeyValuePair.cs +++ b/src/CacheObject/CacheKeyValuePair.cs @@ -92,10 +92,6 @@ namespace UnityExplorer.CacheObject } - protected override bool SetCellEvaluateState(CacheObjectCell cell) - { - // not needed - return false; - } + protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; } } diff --git a/src/CacheObject/CacheListEntry.cs b/src/CacheObject/CacheListEntry.cs index 01e68b1..5f5eefe 100644 --- a/src/CacheObject/CacheListEntry.cs +++ b/src/CacheObject/CacheListEntry.cs @@ -13,7 +13,7 @@ namespace UnityExplorer.CacheObject public override bool ShouldAutoEvaluate => true; public override bool HasArguments => false; - public override bool CanWrite => Owner.CanWrite; + public override bool CanWrite => Owner?.CanWrite ?? false; public void SetListOwner(InteractiveList list, int listIndex) { @@ -37,11 +37,6 @@ namespace UnityExplorer.CacheObject (Owner as InteractiveList).TrySetValueToIndex(value, this.ListIndex); } - - protected override bool SetCellEvaluateState(CacheObjectCell cell) - { - // not needed - return false; - } + protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell) => true; } } diff --git a/src/CacheObject/CacheMember.cs b/src/CacheObject/CacheMember.cs index 7be8da7..cfd7d32 100644 --- a/src/CacheObject/CacheMember.cs +++ b/src/CacheObject/CacheMember.cs @@ -95,7 +95,7 @@ namespace UnityExplorer.CacheObject private static readonly Color evalEnabledColor = new Color(0.15f, 0.25f, 0.15f); private static readonly Color evalDisabledColor = new Color(0.15f, 0.15f, 0.15f); - protected override bool SetCellEvaluateState(CacheObjectCell objectcell) + protected override bool TryAutoEvaluateIfUnitialized(CacheObjectCell objectcell) { var cell = objectcell as CacheMemberCell; @@ -126,13 +126,13 @@ namespace UnityExplorer.CacheObject SetValueState(cell, ValueStateArgs.Default); cell.RefreshSubcontentButton(); - return true; + return false; } if (State == ValueState.NotEvaluated) Evaluate(); - return false; + return true; } public void OnEvaluateClicked() @@ -148,7 +148,7 @@ namespace UnityExplorer.CacheObject this.Evaluator = Pool.Borrow(); Evaluator.OnBorrowedFromPool(this); Evaluator.UIRoot.transform.SetParent((CellView as CacheMemberCell).EvaluateHolder.transform, false); - SetCellEvaluateState(CellView); + TryAutoEvaluateIfUnitialized(CellView); } else { @@ -157,7 +157,7 @@ namespace UnityExplorer.CacheObject else Evaluator.UIRoot.SetActive(true); - SetCellEvaluateState(CellView); + TryAutoEvaluateIfUnitialized(CellView); } } } diff --git a/src/CacheObject/CacheObjectBase.cs b/src/CacheObject/CacheObjectBase.cs index 569f521..9dd1abf 100644 --- a/src/CacheObject/CacheObjectBase.cs +++ b/src/CacheObject/CacheObjectBase.cs @@ -254,8 +254,8 @@ namespace UnityExplorer.CacheObject // Setting cell state from our model - /// Return true if SetCell should abort, false if it should continue. - protected abstract bool SetCellEvaluateState(CacheObjectCell cell); + /// Return false if SetCell should abort, true if it should continue. + protected abstract bool TryAutoEvaluateIfUnitialized(CacheObjectCell cell); public virtual void SetDataToCell(CacheObjectCell cell) { @@ -271,9 +271,21 @@ namespace UnityExplorer.CacheObject IValue.SetLayout(); } - if (SetCellEvaluateState(cell)) + bool evaluated = TryAutoEvaluateIfUnitialized(cell); + + if (cell.CopyButton != null) + { + bool hasEvaluated = State != ValueState.NotEvaluated && State != ValueState.Exception; + cell.CopyButton.Component.gameObject.SetActive(hasEvaluated); + cell.PasteButton.Component.gameObject.SetActive(hasEvaluated && this.CanWrite); + } + + if (!evaluated) return; + // The following only executes if the object has evaluated. + // For members and properties with args, they will return by default now. + switch (State) { case ValueState.Exception: diff --git a/src/CacheObject/IValues/InteractiveList.cs b/src/CacheObject/IValues/InteractiveList.cs index 17d3d95..fb738d2 100644 --- a/src/CacheObject/IValues/InteractiveList.cs +++ b/src/CacheObject/IValues/InteractiveList.cs @@ -32,11 +32,13 @@ namespace UnityExplorer.CacheObject.IValues private PropertyInfo genericIndexer; public int ItemCount => cachedEntries.Count; - private readonly List cachedEntries = new List(); + private readonly List cachedEntries = new(); public ScrollPool ListScrollPool { get; private set; } public Text TopLabel; + private LayoutElement scrollLayout; + private Text NotSupportedLabel; public override void OnBorrowed(CacheObjectBase owner) { @@ -65,6 +67,28 @@ namespace UnityExplorer.CacheObject.IValues cachedEntries.Clear(); } + // List entry scroll pool + + public override void SetLayout() + { + var minHeight = 5f; + + foreach (var cell in ListScrollPool.CellPool) + { + if (cell.Enabled) + minHeight += cell.Rect.rect.height; + } + + this.scrollLayout.minHeight = Math.Min(InspectorPanel.CurrentPanelHeight - 400f, minHeight); + } + + public void OnCellBorrowed(CacheListEntryCell cell) { } // not needed + + public void SetCell(CacheListEntryCell cell, int index) + { + CacheObjectControllerHelper.SetCell(cell, index, cachedEntries, null); + } + // Setting the List value itself to this model public override void SetValue(object value) { @@ -212,32 +236,6 @@ namespace UnityExplorer.CacheObject.IValues } } - // List entry scroll pool - - public override void SetLayout() - { - var minHeight = 5f; - - foreach (var cell in ListScrollPool.CellPool) - { - if (cell.Enabled) - minHeight += cell.Rect.rect.height; - } - - this.scrollLayout.minHeight = Math.Min(InspectorPanel.CurrentPanelHeight - 400f, minHeight); - } - - public void OnCellBorrowed(CacheListEntryCell cell) { } // not needed - - public void SetCell(CacheListEntryCell cell, int index) - { - CacheObjectControllerHelper.SetCell(cell, index, cachedEntries, null); - } - - private LayoutElement scrollLayout; - - private Text NotSupportedLabel; - public override GameObject CreateContent(GameObject parent) { UIRoot = UIFactory.CreateVerticalGroup(parent, "InteractiveList", true, true, true, true, 6, new Vector4(10, 3, 15, 4), diff --git a/src/CacheObject/Views/CacheObjectCell.cs b/src/CacheObject/Views/CacheObjectCell.cs index 485c2bf..ef17d50 100644 --- a/src/CacheObject/Views/CacheObjectCell.cs +++ b/src/CacheObject/Views/CacheObjectCell.cs @@ -7,6 +7,7 @@ using UnityEngine.UI; using UnityExplorer.CacheObject.IValues; using UnityExplorer.Inspectors; using UnityExplorer.UI; +using UnityExplorer.UI.Panels; using UnityExplorer.UI.Widgets; using UniverseLib; using UniverseLib.UI; @@ -47,9 +48,10 @@ namespace UnityExplorer.CacheObject.Views public LayoutElement NameLayout; public GameObject RightGroupContent; public LayoutElement RightGroupLayout; + public GameObject SubContentHolder; public Text NameLabel; - public InputFieldRef HiddenNameLabel; + public InputFieldRef HiddenNameLabel; // for selecting the name label public Text TypeLabel; public Text ValueLabel; public Toggle Toggle; @@ -60,7 +62,11 @@ namespace UnityExplorer.CacheObject.Views public ButtonRef SubContentButton; public ButtonRef ApplyButton; - public GameObject SubContentHolder; + public ButtonRef CopyButton; + public ButtonRef PasteButton; + + public readonly Color subInactiveColor = new(0.23f, 0.23f, 0.23f); + public readonly Color subActiveColor = new(0.23f, 0.33f, 0.23f); protected virtual void ApplyClicked() { @@ -82,26 +88,26 @@ namespace UnityExplorer.CacheObject.Views this.Occupant.OnCellSubContentToggle(); } - public readonly Color subInactiveColor = new Color(0.23f, 0.23f, 0.23f); - public readonly Color subActiveColor = new Color(0.23f, 0.33f, 0.23f); + protected virtual void OnCopyClicked() + { + ClipboardPanel.Copy(this.Occupant.Value); + } + + protected virtual void OnPasteClicked() + { + if (ClipboardPanel.TryPaste(this.Occupant.FallbackType, out object paste)) + this.Occupant.SetUserValue(paste); + } public void RefreshSubcontentButton() { - if (!this.SubContentHolder.activeSelf) - { - this.SubContentButton.ButtonText.text = "▲"; - RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, subInactiveColor, subInactiveColor * 1.3f); - } - else - { - this.SubContentButton.ButtonText.text = "▼"; - RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, subActiveColor, subActiveColor * 1.3f); - } + this.SubContentButton.ButtonText.text = SubContentHolder.activeSelf ? "▼" : "▲"; + Color color = SubContentHolder.activeSelf ? subActiveColor : subInactiveColor; + RuntimeProvider.Instance.SetColorBlock(SubContentButton.Component, color, color * 1.3f); } protected abstract void ConstructEvaluateHolder(GameObject parent); - public virtual GameObject CreateContent(GameObject parent) { // Main layout @@ -158,7 +164,7 @@ namespace UnityExplorer.CacheObject.Views TypeLabel = UIFactory.CreateLabel(rightHoriGroup, "ReturnLabel", "", TextAnchor.MiddleLeft); TypeLabel.horizontalOverflow = HorizontalWrapMode.Wrap; - UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 60, flexibleWidth: 0); + UIFactory.SetLayoutElement(TypeLabel.gameObject, minHeight: 25, flexibleHeight: 150, minWidth: 45, flexibleWidth: 0); // Bool and number value interaction @@ -188,6 +194,24 @@ namespace UnityExplorer.CacheObject.Views ValueLabel.horizontalOverflow = HorizontalWrapMode.Wrap; UIFactory.SetLayoutElement(ValueLabel.gameObject, minHeight: 25, flexibleHeight: 150, flexibleWidth: 9999); + // Copy and Paste buttons + + var buttonHolder = UIFactory.CreateHorizontalGroup(rightHoriGroup, "CopyPasteButtons", false, false, true, true, 4, + bgColor: new(1,1,1,0), childAlignment: TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(buttonHolder, minWidth: 60, flexibleWidth: 0); + + CopyButton = UIFactory.CreateButton(buttonHolder, "CopyButton", "Copy", new Color(0.13f, 0.13f, 0.13f, 1f)); + UIFactory.SetLayoutElement(CopyButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0); + CopyButton.ButtonText.color = Color.yellow; + CopyButton.ButtonText.fontSize = 10; + CopyButton.OnClick += OnCopyClicked; + + PasteButton = UIFactory.CreateButton(buttonHolder, "PasteButton", "Paste", new Color(0.13f, 0.13f, 0.13f, 1f)); + UIFactory.SetLayoutElement(PasteButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0); + PasteButton.ButtonText.color = Color.green; + PasteButton.ButtonText.fontSize = 10; + PasteButton.OnClick += OnPasteClicked; + // Subcontent SubContentHolder = UIFactory.CreateUIObject("SubContent", UIRoot); diff --git a/src/Config/ConfigManager.cs b/src/Config/ConfigManager.cs index f919aad..2c2ef2d 100644 --- a/src/Config/ConfigManager.cs +++ b/src/Config/ConfigManager.cs @@ -38,6 +38,7 @@ namespace UnityExplorer.Config public static ConfigElement OptionsPanelData; public static ConfigElement ConsoleLogData; public static ConfigElement HookManagerData; + public static ConfigElement ClipboardData; internal static readonly Dictionary ConfigElements = new Dictionary(); internal static readonly Dictionary InternalConfigs = new Dictionary(); @@ -132,6 +133,7 @@ namespace UnityExplorer.Config OptionsPanelData = new ConfigElement("OptionsPanel", "", "", true); ConsoleLogData = new ConfigElement("ConsoleLog", "", "", true); HookManagerData = new ConfigElement("HookManager", "", "", true); + ClipboardData = new ConfigElement("Clipboard", "", "", true); } } } diff --git a/src/ExplorerCore.cs b/src/ExplorerCore.cs index 469c00d..44766aa 100644 --- a/src/ExplorerCore.cs +++ b/src/ExplorerCore.cs @@ -16,7 +16,7 @@ namespace UnityExplorer public static class ExplorerCore { public const string NAME = "UnityExplorer"; - public const string VERSION = "4.4.5"; + public const string VERSION = "4.5.0"; public const string AUTHOR = "Sinai"; public const string GUID = "com.sinai.unityexplorer"; @@ -67,6 +67,8 @@ namespace UnityExplorer UIManager.InitUI(); Log($"{NAME} {VERSION} initialized."); + + //InspectorManager.Inspect(typeof(Tests.TestClass)); } /// diff --git a/src/Inspectors/GameObjectInspector.cs b/src/Inspectors/GameObjectInspector.cs index 7851ad3..04a8a97 100644 --- a/src/Inspectors/GameObjectInspector.cs +++ b/src/Inspectors/GameObjectInspector.cs @@ -241,7 +241,6 @@ namespace UnityExplorer.Inspectors } } - #region UI Construction public override GameObject CreateContent(GameObject parent) diff --git a/src/Inspectors/GameObjectWidgets/GameObjectControls.cs b/src/Inspectors/GameObjectWidgets/GameObjectControls.cs index 797db0d..f98c0ca 100644 --- a/src/Inspectors/GameObjectWidgets/GameObjectControls.cs +++ b/src/Inspectors/GameObjectWidgets/GameObjectControls.cs @@ -8,6 +8,7 @@ using UniverseLib.Input; using UnityExplorer.UI; using UniverseLib.UI; using UniverseLib; +using UnityExplorer.UI.Panels; namespace UnityExplorer.Inspectors { @@ -51,6 +52,11 @@ namespace UnityExplorer.Inspectors ConstructTransformControls(); } + private void OnCopyClicked() + { + ClipboardPanel.Copy(this.GOTarget); + } + #region GO Controls private string lastGoName; @@ -467,6 +473,11 @@ namespace UnityExplorer.Inspectors UIFactory.SetLayoutElement(PathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999); PathInput.Component.lineType = InputField.LineType.MultiLineSubmit; + var copyButton = UIFactory.CreateButton(firstRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1)); + copyButton.ButtonText.color = Color.yellow; + UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120); + copyButton.OnClick += OnCopyClicked; + //var pathApplyBtn = UIFactory.CreateButton(firstRow, "PathButton", "Set Parent Path", new Color(0.2f, 0.2f, 0.2f)); //UIFactory.SetLayoutElement(pathApplyBtn.Component.gameObject, minHeight: 25, minWidth: 120); //pathApplyBtn.OnClick += () => { OnPathEndEdit(PathInput.Text); }; diff --git a/src/Inspectors/InspectorTab.cs b/src/Inspectors/InspectorTab.cs index a7ea0fb..9bdfc44 100644 --- a/src/Inspectors/InspectorTab.cs +++ b/src/Inspectors/InspectorTab.cs @@ -9,52 +9,49 @@ using UniverseLib.UI.Models; using UnityExplorer.UI.Widgets; using UniverseLib.UI; using UniverseLib; +using UnityExplorer.UI.Panels; namespace UnityExplorer.Inspectors { public class InspectorTab : IPooledObject { public GameObject UIRoot { get; set; } - public float DefaultHeight => 25f; public ButtonRef TabButton; public Text TabText; - public ButtonRef CloseButton; - private static readonly Color _enabledTabColor = new Color(0.15f, 0.22f, 0.15f); - private static readonly Color _disabledTabColor = new Color(0.13f, 0.13f, 0.13f); + private static readonly Color enabledTabColor = new(0.15f, 0.22f, 0.15f); + private static readonly Color disabledTabColor = new(0.13f, 0.13f, 0.13f); public void SetTabColor(bool active) { - if (active) - RuntimeProvider.Instance.SetColorBlock(TabButton.Component, _enabledTabColor, _enabledTabColor * 1.2f); - else - RuntimeProvider.Instance.SetColorBlock(TabButton.Component, _disabledTabColor, _disabledTabColor * 1.2f); + Color color = active ? enabledTabColor : disabledTabColor; + RuntimeProvider.Instance.SetColorBlock(TabButton.Component, color, color * 1.2f); } public GameObject CreateContent(GameObject parent) { - UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", false, true, true, true, 0, + UIRoot = UIFactory.CreateHorizontalGroup(parent, "TabObject", false, true, true, true, 1, default, new Color(0.13f, 0.13f, 0.13f), childAlignment: TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(UIRoot, minWidth: 200, flexibleWidth: 0); UIRoot.AddComponent(); + UIRoot.AddComponent(); TabButton = UIFactory.CreateButton(UIRoot, "TabButton", ""); - UIFactory.SetLayoutElement(TabButton.Component.gameObject, minWidth: 175, flexibleWidth: 0); + UIFactory.SetLayoutElement(TabButton.Component.gameObject, minWidth: 173, flexibleWidth: 0); UIFactory.SetLayoutGroup(TabButton.Component.gameObject, false, false, true, true, 0, 0, 0, 3); TabText = TabButton.Component.GetComponentInChildren(); - UIFactory.SetLayoutElement(TabText.gameObject, minHeight: 25, minWidth: 175, flexibleWidth: 0); + UIFactory.SetLayoutElement(TabText.gameObject, minHeight: 25, minWidth: 173, flexibleWidth: 0); TabText.alignment = TextAnchor.MiddleLeft; TabText.fontSize = 12; TabText.horizontalOverflow = HorizontalWrapMode.Overflow; - CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.2f, 0.2f, 0.2f, 1)); + CloseButton = UIFactory.CreateButton(UIRoot, "CloseButton", "X", new Color(0.15f, 0.15f, 0.15f, 1)); UIFactory.SetLayoutElement(CloseButton.Component.gameObject, minHeight: 25, minWidth: 25, flexibleWidth: 0); - var closeBtnText = CloseButton.Component.GetComponentInChildren(); - closeBtnText.color = Color.red; + CloseButton.ButtonText.color = Color.red; return UIRoot; } diff --git a/src/Inspectors/ReflectionInspector.cs b/src/Inspectors/ReflectionInspector.cs index 6a4d3f2..243c6d9 100644 --- a/src/Inspectors/ReflectionInspector.cs +++ b/src/Inspectors/ReflectionInspector.cs @@ -327,6 +327,11 @@ namespace UnityExplorer.Inspectors cell.Occupant.IValue.SetLayout(); } + private void OnCopyClicked() + { + ClipboardPanel.Copy(this.Target ?? this.TargetType); + } + // UI Construction private GameObject mainContentHolder; @@ -338,7 +343,10 @@ namespace UnityExplorer.Inspectors // Class name, assembly - var titleHolder = UIFactory.CreateUIObject("TitleHolder", UIRoot); + var topRow = UIFactory.CreateHorizontalGroup(UIRoot, "TopRow", false, false, true, true, 4, default, new(1, 1, 1, 0), TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(topRow, minHeight: 25, flexibleWidth: 9999); + + var titleHolder = UIFactory.CreateUIObject("TitleHolder", topRow); UIFactory.SetLayoutElement(titleHolder, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999); NameText = UIFactory.CreateLabel(titleHolder, "VisibleTitle", "NotSet", TextAnchor.MiddleLeft); @@ -360,6 +368,11 @@ namespace UnityExplorer.Inspectors HiddenNameText.Component.textComponent.color = Color.clear; UIFactory.SetLayoutElement(HiddenNameText.Component.gameObject, minHeight: 35, flexibleHeight: 0, flexibleWidth: 9999); + var copyButton = UIFactory.CreateButton(topRow, "CopyButton", "Copy to Clipboard", new Color(0.2f, 0.2f, 0.2f, 1)); + copyButton.ButtonText.color = Color.yellow; + UIFactory.SetLayoutElement(copyButton.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 0); + copyButton.OnClick += OnCopyClicked; + AssemblyText = UIFactory.CreateLabel(UIRoot, "AssemblyLabel", "not set", TextAnchor.MiddleLeft); UIFactory.SetLayoutElement(AssemblyText.gameObject, minHeight: 25, flexibleWidth: 9999); diff --git a/src/Loader/MelonLoader/MelonLoaderConfigHandler.cs b/src/Loader/MelonLoader/MelonLoaderConfigHandler.cs index a4a9094..dbeda8b 100644 --- a/src/Loader/MelonLoader/MelonLoaderConfigHandler.cs +++ b/src/Loader/MelonLoader/MelonLoaderConfigHandler.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; -using UnityExplorer.Core; using UnityExplorer.Config; namespace UnityExplorer.Loader.ML diff --git a/src/Loader/Standalone/ExplorerStandalone.cs b/src/Loader/Standalone/ExplorerStandalone.cs index 8ac87c3..5ba7a83 100644 --- a/src/Loader/Standalone/ExplorerStandalone.cs +++ b/src/Loader/Standalone/ExplorerStandalone.cs @@ -8,7 +8,6 @@ using UnityExplorer.Config; using UnityExplorer.Loader.STANDALONE; using UnityEngine.EventSystems; using UniverseLib.Input; -using UnityExplorer.Core; #if CPP using UnhollowerRuntimeLib; #endif diff --git a/src/Tests/TestClass.cs b/src/Tests/TestClass.cs index 9522c3b..cc09f64 100644 --- a/src/Tests/TestClass.cs +++ b/src/Tests/TestClass.cs @@ -24,7 +24,10 @@ namespace UnityExplorer.Tests #endif } + public static object LiterallyAnything = null; + // Test enumerables + public static int[,,] MultiDimensionalArray = new int[45, 45, 45]; public static List ListOfInts; public static List>> NestedList; public static IDictionary MixedDictionary; @@ -40,7 +43,12 @@ namespace UnityExplorer.Tests public static CameraClearFlags EnumTest2; public static Color Color = Color.magenta; public static Color32 Color32 = Color.red; - public static string ALongString = new string('#', 10000); + public static string ALongString = new('#', 10000); + + public static float[] AParseTest(ref List arg0, ref float[,] arg1) + { + return new float[] { 1, 2, 3 }; + } public static List RandomList { diff --git a/src/UI/Clipboard/Clipboard.cs b/src/UI/Clipboard/Clipboard.cs deleted file mode 100644 index 58c8432..0000000 --- a/src/UI/Clipboard/Clipboard.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace UnityExplorer.UI -{ - public static class Clipboard - { - public static object Current { get; private set; } - - public static void Init() - { - - } - - public static void Copy(object obj) - { - Current = obj; - } - } -} diff --git a/src/UI/Notification.cs b/src/UI/Notification.cs new file mode 100644 index 0000000..32bf929 --- /dev/null +++ b/src/UI/Notification.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.UI; +using UniverseLib.Input; +using UniverseLib.UI; + +namespace UnityExplorer.UI +{ + public static class Notification + { + private static Text popupLabel; + + private static string _currentNotification; + private static float _timeOfLastNotification; + + public static void Init() + { + ConstructUI(); + } + + public static void ShowMessage(string message) + { + popupLabel.text = message; + _currentNotification = message; + _timeOfLastNotification = Time.realtimeSinceStartup; + + popupLabel.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(InputManager.MousePosition) + (Vector3.up * 25); + } + + public static void Update() + { + if (_currentNotification != null) + { + if (Time.realtimeSinceStartup - _timeOfLastNotification > 2f) + { + _currentNotification = null; + popupLabel.text = ""; + } + } + } + + private static void ConstructUI() + { + + popupLabel = UIFactory.CreateLabel(UIManager.UIRoot, "ClipboardNotification", "", TextAnchor.MiddleCenter); + popupLabel.rectTransform.sizeDelta = new(500, 100); + popupLabel.gameObject.AddComponent(); + var popupGroup = popupLabel.gameObject.AddComponent(); + popupGroup.blocksRaycasts = false; + } + } +} diff --git a/src/UI/Panels/ClipboardPanel.cs b/src/UI/Panels/ClipboardPanel.cs new file mode 100644 index 0000000..5368a87 --- /dev/null +++ b/src/UI/Panels/ClipboardPanel.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.UI; +using UnityExplorer.CacheObject; +using UnityExplorer.CacheObject.Views; +using UnityExplorer.Config; +using UniverseLib; +using UniverseLib.Input; +using UniverseLib.UI; +using UniverseLib.UI.Widgets; + +namespace UnityExplorer.UI.Panels +{ + public class ClipboardPanel : UIPanel + { + public static object Current { get; private set; } + + public override UIManager.Panels PanelType => UIManager.Panels.Clipboard; + public override string Name => "Clipboard"; + public override int MinWidth => 500; + public override int MinHeight => 95; + public override bool CanDragAndResize => true; + public override bool NavButtonWanted => true; + public override bool ShouldSaveActiveState => true; + public override bool ShowByDefault => true; + public override string GetSaveDataFromConfigManager() => ConfigManager.ClipboardData.Value; + public override void DoSaveToConfigElement() => ConfigManager.ClipboardData.Value = this.ToSaveData(); + + private static Text CurrentPasteLabel; + + public static void Copy(object obj) + { + Current = obj; + Notification.ShowMessage("Copied!"); + UpdateCurrentPasteInfo(); + } + + public static bool TryPaste(Type targetType, out object paste) + { + paste = Current; + var pasteType = Current?.GetActualType(); + + if (Current != null && !targetType.IsAssignableFrom(pasteType)) + { + Notification.ShowMessage($"Cannot assign '{pasteType.Name}' to '{targetType.Name}'!"); + return false; + } + + Notification.ShowMessage("Pasted!"); + return true; + } + + public static void ClearClipboard() + { + Current = null; + UpdateCurrentPasteInfo(); + } + + private static void UpdateCurrentPasteInfo() + { + CurrentPasteLabel.text = ToStringUtility.ToStringWithType(Current, typeof(object), false); + } + + private static void InspectClipboard() + { + if (Current.IsNullOrDestroyed()) + { + Notification.ShowMessage("Cannot inspect a null or destroyed object!"); + return; + } + + InspectorManager.Inspect(Current); + } + + protected internal override void DoSetDefaultPosAndAnchors() + { + this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, MinWidth); + this.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, MinHeight); + this.Rect.anchorMin = new Vector2(0.1f, 0.05f); + this.Rect.anchorMax = new Vector2(0.4f, 0.15f); + } + + public override void ConstructPanelContent() + { + this.UIRoot.GetComponent().color = new(0.1f, 0.1f, 0.1f); + + // Actual panel content + + var firstRow = UIFactory.CreateHorizontalGroup(UIRoot, "FirstRow", false, false, true, true, 5, new(2,2,2,2), new(1,1,1,0)); + UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 999); + + // Title for "Current Paste:" + var currentPasteTitle = UIFactory.CreateLabel(firstRow, "CurrentPasteTitle", "Current paste:", TextAnchor.MiddleLeft, color: Color.grey); + UIFactory.SetLayoutElement(currentPasteTitle.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999); + + // Clear clipboard button + var clearButton = UIFactory.CreateButton(firstRow, "ClearPasteButton", "Clear Clipboard"); + UIFactory.SetLayoutElement(clearButton.Component.gameObject, minWidth: 120, minHeight: 25, flexibleWidth: 0); + clearButton.OnClick += () => Copy(null); + + // Current Paste info row + var currentPasteHolder = UIFactory.CreateHorizontalGroup(UIRoot, "SecondRow", false, false, true, true, 0, + new(2, 2, 2, 2), childAlignment: TextAnchor.UpperCenter); + + // Actual current paste info label + CurrentPasteLabel = UIFactory.CreateLabel(currentPasteHolder, "CurrentPasteInfo", "not set", TextAnchor.UpperLeft); + UIFactory.SetLayoutElement(CurrentPasteLabel.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999, flexibleHeight: 999); + UpdateCurrentPasteInfo(); + + // Inspect button + var inspectButton = UIFactory.CreateButton(currentPasteHolder, "InspectButton", "Inspect"); + UIFactory.SetLayoutElement(inspectButton.Component.gameObject, minHeight: 25, flexibleHeight: 0, minWidth: 80, flexibleWidth: 0); + inspectButton.OnClick += InspectClipboard; + } + } +} diff --git a/src/UI/Panels/InspectorPanel.cs b/src/UI/Panels/InspectorPanel.cs index 46cccda..05cb7cd 100644 --- a/src/UI/Panels/InspectorPanel.cs +++ b/src/UI/Panels/InspectorPanel.cs @@ -46,10 +46,7 @@ namespace UnityExplorer.UI.Panels public override string GetSaveDataFromConfigManager() => ConfigManager.InspectorData.Value; - public override void DoSaveToConfigElement() - { - ConfigManager.InspectorData.Value = this.ToSaveData(); - } + public override void DoSaveToConfigElement() => ConfigManager.InspectorData.Value = this.ToSaveData(); protected internal override void DoSetDefaultPosAndAnchors() { diff --git a/src/UI/Panels/PanelDragger.cs b/src/UI/Panels/PanelDragger.cs index 0f7f013..c7e218a 100644 --- a/src/UI/Panels/PanelDragger.cs +++ b/src/UI/Panels/PanelDragger.cs @@ -15,15 +15,33 @@ namespace UnityExplorer.UI.Panels { public class PanelDragger { + private enum MouseState + { + Down, + Held, + NotPressed + } + #region Static public static bool Resizing { get; private set; } + public static bool ResizePrompting => resizeCursorObj && resizeCursorObj.activeSelf; - public static bool ResizePrompting => s_resizeCursorObj && s_resizeCursorObj.activeSelf; + public static GameObject resizeCursorObj; + internal static bool wasAnyDragging; + + internal static List Instances = new(); + + private static bool handledInstanceThisFrame; + + static PanelDragger() + { + UIPanel.OnPanelsReordered += OnPanelsReordered; + } internal static void ForceEnd() { - s_resizeCursorObj.SetActive(false); + resizeCursorObj.SetActive(false); wasAnyDragging = false; Resizing = false; @@ -34,13 +52,6 @@ namespace UnityExplorer.UI.Panels } } - internal static List Instances = new List(); - - static PanelDragger() - { - UIPanel.OnPanelsReordered += OnPanelsReordered; - } - public static void OnPanelsReordered() { Instances.Sort((a, b) => b.Panel.GetSiblingIndex().CompareTo(a.Panel.GetSiblingIndex())); @@ -54,18 +65,9 @@ namespace UnityExplorer.UI.Panels } } - private enum MouseState - { - Down, - Held, - NotPressed - } - - private static bool handledInstanceThisFrame; - public static void UpdateInstances() { - if (!s_resizeCursorObj) + if (!resizeCursorObj) CreateCursorUI(); MouseState state; @@ -99,10 +101,6 @@ namespace UnityExplorer.UI.Panels #endregion - public static GameObject s_resizeCursorObj; - - internal static bool wasAnyDragging; - // Instance public UIPanel UIPanel { get; private set; } @@ -112,27 +110,23 @@ namespace UnityExplorer.UI.Panels public event Action OnFinishResize; public event Action OnFinishDrag; - private readonly RectTransform canvasTransform; - // Dragging public RectTransform DragableArea { get; set; } public bool WasDragging { get; set; } - private Vector2 m_lastDragPosition; + private Vector2 lastDragPosition; // Resizing private const int RESIZE_THICKNESS = 10; - //internal readonly Vector2 minResize = new Vector2(200, 50); - private bool WasResizing { get; set; } - private ResizeTypes m_currentResizeType = ResizeTypes.NONE; - private Vector2 m_lastResizePos; + private ResizeTypes currentResizeType = ResizeTypes.NONE; + private Vector2 lastResizePos; - private bool WasHoveringResize => s_resizeCursorObj.activeInHierarchy; + private bool WasHoveringResize => resizeCursorObj.activeInHierarchy; - private ResizeTypes m_lastResizeHoverType; + private ResizeTypes lastResizeHoverType; - private Rect m_totalResizeRect; + private Rect totalResizeRect; public PanelDragger(RectTransform dragArea, RectTransform panelToDrag, UIPanel panel) { @@ -141,16 +135,13 @@ namespace UnityExplorer.UI.Panels DragableArea = dragArea; Panel = panelToDrag; - if (!canvasTransform) - canvasTransform = Panel.GetComponentInParent().GetComponent(); - UpdateResizeCache(); } public void Destroy() { - if (s_resizeCursorObj) - GameObject.Destroy(s_resizeCursorObj); + if (resizeCursorObj) + GameObject.Destroy(resizeCursorObj); if (Instances.Contains(this)) Instances.Remove(this); @@ -166,7 +157,7 @@ namespace UnityExplorer.UI.Panels Vector3 dragPos = DragableArea.InverseTransformPoint(rawMousePos); bool inDragPos = DragableArea.rect.Contains(dragPos); - if (WasHoveringResize && s_resizeCursorObj) + if (WasHoveringResize && resizeCursorObj) UpdateHoverImagePos(); switch (state) @@ -243,15 +234,15 @@ namespace UnityExplorer.UI.Panels { wasAnyDragging = true; WasDragging = true; - m_lastDragPosition = InputManager.MousePosition; + lastDragPosition = InputManager.MousePosition; } public void OnDrag() { var mousePos = InputManager.MousePosition; - Vector2 diff = (Vector2)mousePos - m_lastDragPosition; - m_lastDragPosition = mousePos; + Vector2 diff = (Vector2)mousePos - lastDragPosition; + lastDragPosition = mousePos; Panel.localPosition = Panel.localPosition + (Vector3)diff; @@ -296,7 +287,7 @@ namespace UnityExplorer.UI.Panels private void UpdateResizeCache() { - m_totalResizeRect = new Rect(Panel.rect.x - RESIZE_THICKNESS + 1, + totalResizeRect = new Rect(Panel.rect.x - RESIZE_THICKNESS + 1, Panel.rect.y - RESIZE_THICKNESS + 1, Panel.rect.width + DBL_THICKESS - 2, Panel.rect.height + DBL_THICKESS - 2); @@ -305,34 +296,34 @@ namespace UnityExplorer.UI.Panels if (AllowDragAndResize) { m_resizeMask[ResizeTypes.Bottom] = new Rect( - m_totalResizeRect.x, - m_totalResizeRect.y, - m_totalResizeRect.width, + totalResizeRect.x, + totalResizeRect.y, + totalResizeRect.width, RESIZE_THICKNESS); m_resizeMask[ResizeTypes.Left] = new Rect( - m_totalResizeRect.x, - m_totalResizeRect.y, + totalResizeRect.x, + totalResizeRect.y, RESIZE_THICKNESS, - m_totalResizeRect.height); + totalResizeRect.height); m_resizeMask[ResizeTypes.Top] = new Rect( - m_totalResizeRect.x, + totalResizeRect.x, Panel.rect.y + Panel.rect.height - 2, - m_totalResizeRect.width, + totalResizeRect.width, RESIZE_THICKNESS); m_resizeMask[ResizeTypes.Right] = new Rect( - m_totalResizeRect.x + Panel.rect.width + RESIZE_THICKNESS - 2, - m_totalResizeRect.y, + totalResizeRect.x + Panel.rect.width + RESIZE_THICKNESS - 2, + totalResizeRect.y, RESIZE_THICKNESS, - m_totalResizeRect.height); + totalResizeRect.height); } } private bool MouseInResizeArea(Vector2 mousePos) { - return m_totalResizeRect.Contains(mousePos); + return totalResizeRect.Contains(mousePos); } private ResizeTypes GetResizeType(Vector2 mousePos) @@ -361,16 +352,16 @@ namespace UnityExplorer.UI.Panels public void OnHoverResize(ResizeTypes resizeType) { - if (WasHoveringResize && m_lastResizeHoverType == resizeType) + if (WasHoveringResize && lastResizeHoverType == resizeType) return; // we are entering resize, or the resize type has changed. //WasHoveringResize = true; - m_lastResizeHoverType = resizeType; + lastResizeHoverType = resizeType; - s_resizeCursorObj.SetActive(true); - s_resizeCursorObj.transform.SetAsLastSibling(); + resizeCursorObj.SetActive(true); + resizeCursorObj.transform.SetAsLastSibling(); // set the rotation for the resize icon float iconRotation = 0f; @@ -387,9 +378,9 @@ namespace UnityExplorer.UI.Panels iconRotation = 135f; break; } - Quaternion rot = s_resizeCursorObj.transform.rotation; + Quaternion rot = resizeCursorObj.transform.rotation; rot.eulerAngles = new Vector3(0, 0, iconRotation); - s_resizeCursorObj.transform.rotation = rot; + resizeCursorObj.transform.rotation = rot; UpdateHoverImagePos(); } @@ -397,19 +388,19 @@ namespace UnityExplorer.UI.Panels // update the resize icon position to be above the mouse private void UpdateHoverImagePos() { - s_resizeCursorObj.transform.localPosition = canvasTransform.InverseTransformPoint(InputManager.MousePosition); + resizeCursorObj.transform.localPosition = UIManager.UIRootRect.InverseTransformPoint(InputManager.MousePosition); } public void OnHoverResizeEnd() { //WasHoveringResize = false; - s_resizeCursorObj.SetActive(false); + resizeCursorObj.SetActive(false); } public void OnBeginResize(ResizeTypes resizeType) { - m_currentResizeType = resizeType; - m_lastResizePos = InputManager.MousePosition; + currentResizeType = resizeType; + lastResizePos = InputManager.MousePosition; WasResizing = true; Resizing = true; } @@ -417,15 +408,15 @@ namespace UnityExplorer.UI.Panels public void OnResize() { Vector3 mousePos = InputManager.MousePosition; - Vector2 diff = m_lastResizePos - (Vector2)mousePos; + Vector2 diff = lastResizePos - (Vector2)mousePos; - if ((Vector2)mousePos == m_lastResizePos) + if ((Vector2)mousePos == lastResizePos) return; if (mousePos.x < 0 || mousePos.y < 0 || mousePos.x > Screen.width || mousePos.y > Screen.height) return; - m_lastResizePos = mousePos; + lastResizePos = mousePos; float diffX = (float)((decimal)diff.x / Screen.width); float diffY = (float)((decimal)diff.y / Screen.height); @@ -433,14 +424,14 @@ namespace UnityExplorer.UI.Panels Vector2 anchorMin = Panel.anchorMin; Vector2 anchorMax = Panel.anchorMax; - if (m_currentResizeType.HasFlag(ResizeTypes.Left)) + if (currentResizeType.HasFlag(ResizeTypes.Left)) anchorMin.x -= diffX; - else if (m_currentResizeType.HasFlag(ResizeTypes.Right)) + else if (currentResizeType.HasFlag(ResizeTypes.Right)) anchorMax.x -= diffX; - if (m_currentResizeType.HasFlag(ResizeTypes.Top)) + if (currentResizeType.HasFlag(ResizeTypes.Top)) anchorMax.y -= diffY; - else if (m_currentResizeType.HasFlag(ResizeTypes.Bottom)) + else if (currentResizeType.HasFlag(ResizeTypes.Bottom)) anchorMin.y -= diffY; var prevMin = Panel.anchorMin; @@ -475,13 +466,13 @@ namespace UnityExplorer.UI.Panels try { var text = UIFactory.CreateLabel(UIManager.UIRoot, "ResizeCursor", "↔", TextAnchor.MiddleCenter, Color.white, true, 35); - s_resizeCursorObj = text.gameObject; + resizeCursorObj = text.gameObject; - RectTransform rect = s_resizeCursorObj.GetComponent(); + RectTransform rect = resizeCursorObj.GetComponent(); rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, 64); rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, 64); - s_resizeCursorObj.SetActive(false); + resizeCursorObj.SetActive(false); } catch (Exception e) { diff --git a/src/UI/Panels/UIPanel.cs b/src/UI/Panels/UIPanel.cs index 59c75f2..844dd63 100644 --- a/src/UI/Panels/UIPanel.cs +++ b/src/UI/Panels/UIPanel.cs @@ -23,8 +23,8 @@ namespace UnityExplorer.UI.Panels public static event Action OnPanelsReordered; public static event Action OnClickedOutsidePanels; - internal static readonly List instances = new List(); - internal static readonly Dictionary transformToPanelDict = new Dictionary(); + internal static readonly List instances = new(); + internal static readonly Dictionary transformToPanelDict = new(); public static void UpdateFocus() { diff --git a/src/UI/Panels/UiInspectorResultsPanel.cs b/src/UI/Panels/UiInspectorResultsPanel.cs index 18edf25..b5f2baf 100644 --- a/src/UI/Panels/UiInspectorResultsPanel.cs +++ b/src/UI/Panels/UiInspectorResultsPanel.cs @@ -27,17 +27,6 @@ namespace UnityExplorer.UI.Panels private ButtonListHandler dataHandler; private ScrollPool buttonScrollPool; - public override void ConstructPanelContent() - { - dataHandler = new ButtonListHandler(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked); - - buttonScrollPool = UIFactory.CreateScrollPool(this.content, "ResultsList", out GameObject scrollObj, - out GameObject scrollContent); - - buttonScrollPool.Initialize(dataHandler); - UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); - } - public void ShowResults() { dataHandler.RefreshData(); @@ -65,6 +54,17 @@ namespace UnityExplorer.UI.Panels cell.Button.ButtonText.text = $"{obj.name} ({obj.transform.GetTransformPath(true)})"; } + public override void ConstructPanelContent() + { + dataHandler = new ButtonListHandler(buttonScrollPool, GetEntries, SetCell, ShouldDisplayCell, OnCellClicked); + + buttonScrollPool = UIFactory.CreateScrollPool(this.content, "ResultsList", out GameObject scrollObj, + out GameObject scrollContent); + + buttonScrollPool.Initialize(dataHandler); + UIFactory.SetLayoutElement(scrollObj, flexibleHeight: 9999); + } + protected internal override void DoSetDefaultPosAndAnchors() { this.Rect.anchorMin = new Vector2(0.5f, 0.5f); diff --git a/src/UI/UIManager.cs b/src/UI/UIManager.cs index 3055e3e..64cfa38 100644 --- a/src/UI/UIManager.cs +++ b/src/UI/UIManager.cs @@ -35,6 +35,7 @@ namespace UnityExplorer.UI MouseInspector, UIInspectorResults, HookManager, + Clipboard } public enum VerticalAnchor @@ -49,12 +50,15 @@ namespace UnityExplorer.UI private static UIBase uiBase; public static GameObject UIRoot => uiBase?.RootObject; + public static RectTransform UIRootRect => _uiRootRect ??= UIRoot.GetComponent(); + private static RectTransform _uiRootRect; internal static GameObject PanelHolder { get; private set; } - private static readonly Dictionary UIPanels = new Dictionary(); + private static readonly Dictionary UIPanels = new(); public static RectTransform NavBarRect; public static GameObject NavbarTabButtonHolder; + private static readonly Vector2 NAVBAR_DIMENSIONS = new(1020f, 35f); private static ButtonRef closeBtn; private static ButtonRef pauseBtn; @@ -62,6 +66,9 @@ namespace UnityExplorer.UI private static bool pauseButtonPausing; private static float lastTimeScale; + private static int lastScreenWidth; + private static int lastScreenHeight; + public static bool ShowMenu { get => uiBase != null && uiBase.Enabled; @@ -83,6 +90,7 @@ namespace UnityExplorer.UI lastScreenWidth = Screen.width; lastScreenHeight = Screen.height; + // Create UI. CreatePanelHolder(); CreateTopNavBar(); @@ -93,6 +101,7 @@ namespace UnityExplorer.UI UIPanels.Add(Panels.Inspector, new InspectorPanel()); UIPanels.Add(Panels.CSConsole, new CSConsolePanel()); UIPanels.Add(Panels.HookManager, new HookManagerPanel()); + UIPanels.Add(Panels.Clipboard, new ClipboardPanel()); UIPanels.Add(Panels.ConsoleLog, new LogPanel()); UIPanels.Add(Panels.Options, new OptionsPanel()); UIPanels.Add(Panels.UIInspectorResults, new UiInspectorResultsPanel()); @@ -102,8 +111,8 @@ namespace UnityExplorer.UI panel.ConstructUI(); // Call some initialize methods + Notification.Init(); ConsoleController.Init(); - Clipboard.Init(); // Add this listener to prevent ScrollPool doing anything while we are resizing panels ScrollPool.writingLockedListeners.Add(() => !PanelDragger.Resizing); @@ -120,9 +129,6 @@ namespace UnityExplorer.UI // Main UI Update loop - private static int lastScreenWidth; - private static int lastScreenHeight; - public static void Update() { if (!UIRoot) @@ -135,6 +141,9 @@ namespace UnityExplorer.UI return; } + // Update Notification modal + Notification.Update(); + // Check forceUnlockMouse toggle if (InputManager.GetKeyDown(ConfigManager.Force_Unlock_Toggle.Value)) UniverseLib.Config.ConfigManager.Force_Unlock_Mouse = !UniverseLib.Config.ConfigManager.Force_Unlock_Mouse; @@ -208,14 +217,14 @@ namespace UnityExplorer.UI NavBarRect.anchorMin = new Vector2(0.5f, 1f); NavBarRect.anchorMax = new Vector2(0.5f, 1f); NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 0); - NavBarRect.sizeDelta = new Vector2(1080f, 35f); + NavBarRect.sizeDelta = NAVBAR_DIMENSIONS; break; case VerticalAnchor.Bottom: NavBarRect.anchorMin = new Vector2(0.5f, 0f); NavBarRect.anchorMax = new Vector2(0.5f, 0f); NavBarRect.anchoredPosition = new Vector2(NavBarRect.anchoredPosition.x, 35); - NavBarRect.sizeDelta = new Vector2(1080f, 35f); + NavBarRect.sizeDelta = NAVBAR_DIMENSIONS; break; } } diff --git a/src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs b/src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs index a72393f..bb9db57 100644 --- a/src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs +++ b/src/UI/Widgets/EvaluateWidget/EvaluateWidget.cs @@ -42,8 +42,6 @@ namespace UnityExplorer.UI.Widgets SetArgRows(); this.UIRoot.SetActive(true); - - InspectorManager.OnInspectedTabsChanged += InspectorManager_OnInspectedTabsChanged; } public void OnReturnToPool() @@ -63,14 +61,6 @@ namespace UnityExplorer.UI.Widgets genericHandlers = null; this.Owner = null; - - InspectorManager.OnInspectedTabsChanged -= InspectorManager_OnInspectedTabsChanged; - } - - private void InspectorManager_OnInspectedTabsChanged() - { - foreach (var handler in this.paramHandlers) - handler.PopulateDropdown(); } public Type[] TryParseGenericArguments() diff --git a/src/UI/Widgets/EvaluateWidget/ParameterHandler.cs b/src/UI/Widgets/EvaluateWidget/ParameterHandler.cs index c71af61..7a8ef4c 100644 --- a/src/UI/Widgets/EvaluateWidget/ParameterHandler.cs +++ b/src/UI/Widgets/EvaluateWidget/ParameterHandler.cs @@ -1,9 +1,12 @@ -using System; +using HarmonyLib; +using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Reflection; +using UnityEngine; using UnityEngine.UI; using UnityExplorer.CacheObject.IValues; +using UnityExplorer.UI.Panels; using UnityExplorer.UI.Widgets.AutoComplete; using UniverseLib; using UniverseLib.UI; @@ -15,11 +18,15 @@ namespace UnityExplorer.UI.Widgets private ParameterInfo paramInfo; private Type paramType; - internal Dropdown dropdown; - private bool usingDropdown; internal EnumCompleter enumCompleter; private ButtonRef enumHelperButton; + private bool usingBasicLabel; + private object basicValue; + private GameObject basicLabelHolder; + private Text basicLabel; + private ButtonRef pasteButton; + public void OnBorrowed(EvaluateWidget evaluator, ParameterInfo paramInfo) { this.evaluator = evaluator; @@ -34,8 +41,10 @@ namespace UnityExplorer.UI.Widgets if (ParseUtility.CanParse(paramType) || typeof(Type).IsAssignableFrom(paramType)) { + usingBasicLabel = false; + this.inputField.Component.gameObject.SetActive(true); - this.dropdown.gameObject.SetActive(false); + this.basicLabelHolder.SetActive(false); this.typeCompleter.Enabled = typeof(Type).IsAssignableFrom(paramType); this.enumCompleter.Enabled = paramType.IsEnum; this.enumHelperButton.Component.gameObject.SetActive(paramType.IsEnum); @@ -63,16 +72,15 @@ namespace UnityExplorer.UI.Widgets else { // non-parsable, and not a Type + usingBasicLabel = true; + this.inputField.Component.gameObject.SetActive(false); - this.dropdown.gameObject.SetActive(true); + this.basicLabelHolder.SetActive(true); this.typeCompleter.Enabled = false; this.enumCompleter.Enabled = false; this.enumHelperButton.Component.gameObject.SetActive(false); - usingDropdown = true; - PopulateDropdown(); - - InspectorManager.OnInspectedTabsChanged += PopulateDropdown; + SetDisplayedValueFromPaste(); } } @@ -81,109 +89,89 @@ namespace UnityExplorer.UI.Widgets this.evaluator = null; this.paramInfo = null; - usingDropdown = false; - this.enumCompleter.Enabled = false; this.typeCompleter.Enabled = false; this.inputField.Text = ""; - InspectorManager.OnInspectedTabsChanged -= PopulateDropdown; + this.usingBasicLabel = false; + this.basicValue = null; } public object Evaluate() { - if (!usingDropdown) + if (usingBasicLabel) + return basicValue; + + var input = this.inputField.Text; + + if (typeof(Type).IsAssignableFrom(paramType)) + return ReflectionUtility.GetTypeByName(input); + + if (paramType == typeof(string)) + return input; + + if (string.IsNullOrEmpty(input)) { - var input = this.inputField.Text; - - if (typeof(Type).IsAssignableFrom(paramType)) - return ReflectionUtility.GetTypeByName(input); - - if (paramType == typeof(string)) - return input; - - if (string.IsNullOrEmpty(input)) - { - if (paramInfo.IsOptional) - return paramInfo.DefaultValue; - else - return null; - } - - if (!ParseUtility.TryParse(input, paramType, out object parsed, out Exception ex)) - { - ExplorerCore.LogWarning($"Cannot parse argument '{paramInfo.Name}' ({paramInfo.ParameterType.Name})" + - $"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}"); - return null; - } + if (paramInfo.IsOptional) + return paramInfo.DefaultValue; else - return parsed; + return null; + } + + if (!ParseUtility.TryParse(input, paramType, out object parsed, out Exception ex)) + { + ExplorerCore.LogWarning($"Cannot parse argument '{paramInfo.Name}' ({paramInfo.ParameterType.Name})" + + $"{(ex == null ? "" : $", {ex.GetType().Name}: {ex.Message}")}"); + return null; } else + return parsed; + } + + private void OnPasteClicked() + { + if (ClipboardPanel.TryPaste(this.paramType, out object paste)) { - if (dropdown.value == 0) - return null; + basicValue = paste; + SetDisplayedValueFromPaste(); + } + } + + private void SetDisplayedValueFromPaste() + { + if (usingBasicLabel) + basicLabel.text = ToStringUtility.ToStringWithType(basicValue, paramType, false); + else + { + if (typeof(Type).IsAssignableFrom(paramType)) + inputField.Text = (basicValue as Type).FullDescription(); else - return dropdownUnderlyingValues[dropdown.value]; + inputField.Text = ParseUtility.ToStringForInput(basicValue, paramType); } } - private object[] dropdownUnderlyingValues; - - internal void PopulateDropdown() - { - if (!usingDropdown) - return; - - dropdown.options.Clear(); - var underlyingValues = new List(); - - dropdown.options.Add(new Dropdown.OptionData("null")); - underlyingValues.Add(null); - - var argType = paramType; - - int tabIndex = 0; - foreach (var tab in InspectorManager.Inspectors) - { - tabIndex++; - - if (argType.IsAssignableFrom(tab.Target.GetActualType())) - { - dropdown.options.Add(new Dropdown.OptionData($"Tab {tabIndex}: {tab.Tab.TabText.text}")); - underlyingValues.Add(tab.Target); - } - } - - dropdownUnderlyingValues = underlyingValues.ToArray(); - } - - private void EnumHelper_OnClick() - { - enumCompleter.HelperButtonClicked(); - } - public override void CreateSpecialContent() { + enumCompleter = new(paramType, this.inputField) + { + Enabled = false + }; + enumHelperButton = UIFactory.CreateButton(UIRoot, "EnumHelper", "▼"); UIFactory.SetLayoutElement(enumHelperButton.Component.gameObject, minWidth: 25, minHeight: 25, flexibleWidth: 0, flexibleHeight: 0); - enumHelperButton.OnClick += EnumHelper_OnClick; + enumHelperButton.OnClick += enumCompleter.HelperButtonClicked; - var dropdownObj = UIFactory.CreateDropdown(UIRoot, out dropdown, "Select argument...", 14, (int val) => - { - //ArgDropdownChanged(val); - }); - UIFactory.SetLayoutElement(dropdownObj, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000); - dropdownObj.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; + basicLabelHolder = UIFactory.CreateHorizontalGroup(UIRoot, "BasicLabelHolder", true, true, true, true, bgColor: new(0.1f, 0.1f, 0.1f)); + UIFactory.SetLayoutElement(basicLabelHolder, minHeight: 25, flexibleHeight: 50, minWidth: 100, flexibleWidth: 1000); + basicLabel = UIFactory.CreateLabel(basicLabelHolder, "BasicLabel", "null", TextAnchor.MiddleLeft); + basicLabel.gameObject.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; - enumCompleter = new EnumCompleter(paramType, this.inputField); - enumCompleter.Enabled = false; + pasteButton = UIFactory.CreateButton(UIRoot, "PasteButton", "Paste", new Color(0.13f, 0.13f, 0.13f, 1f)); + UIFactory.SetLayoutElement(pasteButton.Component.gameObject, minHeight: 25, minWidth: 28, flexibleWidth: 0); + pasteButton.ButtonText.color = Color.green; + pasteButton.ButtonText.fontSize = 10; + pasteButton.OnClick += OnPasteClicked; } - - //private void ArgDropdownChanged(int value) - //{ - // // not needed - //} } } diff --git a/src/UnityExplorer.csproj b/src/UnityExplorer.csproj index caf7632..cde598e 100644 --- a/src/UnityExplorer.csproj +++ b/src/UnityExplorer.csproj @@ -172,13 +172,13 @@ False - packages\UniverseLib.1.0.4\lib\net35\UniverseLib.Mono.dll + packages\UniverseLib.1.0.6\lib\net35\UniverseLib.Mono.dll - packages\UniverseLib.1.0.4\lib\net472\UniverseLib.IL2CPP.dll + packages\UniverseLib.1.0.6\lib\net472\UniverseLib.IL2CPP.dll ..\lib\Il2CppAssemblyUnhollower\UnhollowerBaseLib\bin\Release\net4.7.2\UnhollowerBaseLib.dll @@ -222,7 +222,6 @@ - @@ -257,6 +256,8 @@ + + @@ -276,7 +277,7 @@ - + diff --git a/src/packages.config b/src/packages.config index 5cf0826..e001b03 100644 --- a/src/packages.config +++ b/src/packages.config @@ -4,5 +4,5 @@ - + \ No newline at end of file