diff --git a/src/Inspectors/GameObjectInspector.cs b/src/Inspectors/GameObjectInspector.cs index 4c06ca2..be6cb24 100644 --- a/src/Inspectors/GameObjectInspector.cs +++ b/src/Inspectors/GameObjectInspector.cs @@ -18,11 +18,11 @@ namespace UnityExplorer.Inspectors { public class GameObjectInspector : InspectorBase { - public GameObject GOTarget => Target as GameObject; + public new GameObject Target => base.Target as GameObject; public GameObject Content; - public GameObjectControls GOControls; + public GameObjectControls Controls; public TransformTree TransformTree; private ScrollPool transformScroll; @@ -38,10 +38,10 @@ namespace UnityExplorer.Inspectors { base.OnBorrowedFromPool(target); - Target = target as GameObject; + base.Target = target as GameObject; - GOControls.UpdateGameObjectInfo(true, true); - GOControls.UpdateTransformControlValues(true); + Controls.UpdateGameObjectInfo(true, true); + Controls.TransformControl.UpdateTransformControlValues(true); RuntimeHelper.StartCoroutine(InitCoroutine()); } @@ -76,9 +76,9 @@ namespace UnityExplorer.Inspectors public void OnTransformCellClicked(GameObject newTarget) { - this.Target = newTarget; - GOControls.UpdateGameObjectInfo(true, true); - GOControls.UpdateTransformControlValues(true); + base.Target = newTarget; + Controls.UpdateGameObjectInfo(true, true); + Controls.TransformControl.UpdateTransformControlValues(true); TransformTree.RefreshData(true, false, true, false); UpdateComponents(); } @@ -90,21 +90,21 @@ namespace UnityExplorer.Inspectors if (!this.IsActive) return; - if (Target.IsNullOrDestroyed(false)) + if (base.Target.IsNullOrDestroyed(false)) { InspectorManager.ReleaseInspector(this); return; } - GOControls.UpdateVectorSlider(); - GOControls.UpdateTransformControlValues(false); + Controls.UpdateVectorSlider(); + Controls.TransformControl.UpdateTransformControlValues(false); // Slow update if (timeOfLastUpdate.OccuredEarlierThan(1)) { timeOfLastUpdate = Time.realtimeSinceStartup; - GOControls.UpdateGameObjectInfo(false, false); + Controls.UpdateGameObjectInfo(false, false); TransformTree.RefreshData(true, false, false, false); UpdateComponents(); @@ -115,12 +115,12 @@ namespace UnityExplorer.Inspectors private IEnumerable GetTransformEntries() { - if (!GOTarget) + if (!Target) return Enumerable.Empty(); cachedChildren.Clear(); - for (int i = 0; i < GOTarget.transform.childCount; i++) - cachedChildren.Add(GOTarget.transform.GetChild(i).gameObject); + for (int i = 0; i < Target.transform.childCount; i++) + cachedChildren.Add(Target.transform.GetChild(i).gameObject); return cachedChildren; } @@ -130,11 +130,11 @@ namespace UnityExplorer.Inspectors private readonly List behaviourEnabledStates = new(); // ComponentList.GetRootEntriesMethod - private List GetComponentEntries() => GOTarget ? componentEntries : Enumerable.Empty().ToList(); + private List GetComponentEntries() => Target ? componentEntries : Enumerable.Empty().ToList(); public void UpdateComponents() { - if (!GOTarget) + if (!Target) { componentEntries.Clear(); compInstanceIDs.Clear(); @@ -146,8 +146,8 @@ namespace UnityExplorer.Inspectors } // Check if we actually need to refresh the component cells or not. - IEnumerable comps = GOTarget.GetComponents(); - IEnumerable behaviours = GOTarget.GetComponents(); + IEnumerable comps = Target.GetComponents(); + IEnumerable behaviours = Target.GetComponents(); bool needRefresh = false; @@ -231,7 +231,7 @@ namespace UnityExplorer.Inspectors private void OnAddChildClicked(string input) { GameObject newObject = new(input); - newObject.transform.parent = GOTarget.transform; + newObject.transform.parent = Target.transform; TransformTree.RefreshData(true, false, true, false); } @@ -242,7 +242,7 @@ namespace UnityExplorer.Inspectors { try { - RuntimeHelper.AddComponent(GOTarget, type); + RuntimeHelper.AddComponent(Target, type); UpdateComponents(); } catch (Exception ex) @@ -270,7 +270,7 @@ namespace UnityExplorer.Inspectors UIFactory.SetLayoutGroup(Content, spacing: 3, padTop: 2, padBottom: 2, padLeft: 2, padRight: 2); // Construct GO Controls - GOControls = new GameObjectControls(this); + Controls = new GameObjectControls(this); ConstructLists(); diff --git a/src/Inspectors/GameObjectWidgets/GameObjectControls.cs b/src/Inspectors/GameObjectWidgets/GameObjectControls.cs deleted file mode 100644 index b1fc1c8..0000000 --- a/src/Inspectors/GameObjectWidgets/GameObjectControls.cs +++ /dev/null @@ -1,696 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using UnityEngine.UI; -using UnityExplorer.UI; -using UnityExplorer.UI.Panels; -using UniverseLib; -using UniverseLib.Input; -using UniverseLib.UI; -using UniverseLib.UI.Models; -using UniverseLib.Utility; - -namespace UnityExplorer.Inspectors -{ - public class GameObjectControls - { - public GameObjectInspector Parent; - private GameObject GOTarget => Parent.GOTarget; - - // Top info - - private ButtonRef ViewParentButton; - private InputFieldRef PathInput; - - private InputFieldRef NameInput; - private Toggle ActiveSelfToggle; - private Text ActiveSelfText; - private Toggle IsStaticToggle; - - private InputFieldRef SceneInput; - private InputFieldRef InstanceIDInput; - private InputFieldRef TagInput; - - private Dropdown LayerDropdown; - private Dropdown FlagsDropdown; - - // transform controls - - private TransformControl PositionControl; - private TransformControl LocalPositionControl; - private TransformControl RotationControl; - private TransformControl ScaleControl; - - private VectorSlider currentSlidingVectorControl; - private float currentVectorValue; - - public GameObjectControls(GameObjectInspector parent) - { - this.Parent = parent; - - ConstructTopInfo(); - ConstructTransformControls(); - } - - private void OnCopyClicked() - { - ClipboardPanel.Copy(this.GOTarget); - } - - #region GO Controls - - private string lastGoName; - private string lastPath; - private bool lastParentState; - private int lastSceneHandle; - private string lastTag; - private int lastLayer; - private int lastFlags; - - public void UpdateGameObjectInfo(bool firstUpdate, bool force) - { - if (firstUpdate) - { - InstanceIDInput.Text = GOTarget.GetInstanceID().ToString(); - } - - if (force || (!NameInput.Component.isFocused && GOTarget.name != lastGoName)) - { - lastGoName = GOTarget.name; - Parent.Tab.TabText.text = $"[G] {GOTarget.name}"; - NameInput.Text = GOTarget.name; - } - - if (force || !PathInput.Component.isFocused) - { - string path = GOTarget.transform.GetTransformPath(); - if (path != lastPath) - { - lastPath = path; - PathInput.Text = path; - } - } - - if (force || GOTarget.transform.parent != lastParentState) - { - lastParentState = GOTarget.transform.parent; - ViewParentButton.Component.interactable = lastParentState; - if (lastParentState) - { - ViewParentButton.ButtonText.color = Color.white; - ViewParentButton.ButtonText.text = "◄ View Parent"; - } - else - { - ViewParentButton.ButtonText.color = Color.grey; - ViewParentButton.ButtonText.text = "No parent"; - } - } - - if (force || GOTarget.activeSelf != ActiveSelfToggle.isOn) - { - ActiveSelfToggle.Set(GOTarget.activeSelf, false); - ActiveSelfText.color = ActiveSelfToggle.isOn ? Color.green : Color.red; - } - - if (force || GOTarget.isStatic != IsStaticToggle.isOn) - { - IsStaticToggle.Set(GOTarget.isStatic, false); - } - - if (force || GOTarget.scene.handle != lastSceneHandle) - { - lastSceneHandle = GOTarget.scene.handle; - SceneInput.Text = GOTarget.scene.IsValid() ? GOTarget.scene.name : "None (Asset/Resource)"; - } - - if (force || (!TagInput.Component.isFocused && GOTarget.tag != lastTag)) - { - lastTag = GOTarget.tag; - TagInput.Text = lastTag; - } - - if (force || (GOTarget.layer != lastLayer)) - { - lastLayer = GOTarget.layer; - LayerDropdown.value = GOTarget.layer; - } - - if (force || ((int)GOTarget.hideFlags != lastFlags)) - { - lastFlags = (int)GOTarget.hideFlags; - FlagsDropdown.captionText.text = GOTarget.hideFlags.ToString(); - } - } - - private void OnViewParentClicked() - { - if (this.GOTarget && this.GOTarget.transform.parent) - { - Parent.OnTransformCellClicked(this.GOTarget.transform.parent.gameObject); - } - } - - private void OnPathEndEdit(string input) - { - lastPath = input; - - if (string.IsNullOrEmpty(input)) - { - DoSetParent(null); - } - else - { - Transform parentToSet = null; - - if (input.EndsWith("/")) - input = input.Remove(input.Length - 1); - - // try the easy way - if (GameObject.Find(input) is GameObject found) - { - parentToSet = found.transform; - } - else - { - // look for inactive objects - string name = input.Split('/').Last(); - UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject)); - List shortList = new(); - foreach (UnityEngine.Object obj in allObjects) - if (obj.name == name) shortList.Add(obj.TryCast()); - foreach (GameObject go in shortList) - { - string path = go.transform.GetTransformPath(true); - if (path.EndsWith("/")) - path = path.Remove(path.Length - 1); - if (path == input) - { - parentToSet = go.transform; - break; - } - } - } - - if (parentToSet) - DoSetParent(parentToSet); - else - { - ExplorerCore.LogWarning($"Could not find any GameObject name or path '{input}'!"); - UpdateGameObjectInfo(false, true); - } - } - - } - - private void DoSetParent(Transform transform) - { - ExplorerCore.Log($"Setting target's transform parent to: {(transform == null ? "null" : $"'{transform.name}'")}"); - - if (GOTarget.GetComponent()) - GOTarget.transform.SetParent(transform, false); - else - GOTarget.transform.parent = transform; - - UpdateGameObjectInfo(false, false); - UpdateTransformControlValues(false); - } - - private void OnNameEndEdit(string value) - { - GOTarget.name = value; - UpdateGameObjectInfo(false, true); - } - - private void OnActiveSelfToggled(bool value) - { - GOTarget.SetActive(value); - UpdateGameObjectInfo(false, true); - } - - private void OnTagEndEdit(string value) - { - try - { - GOTarget.tag = value; - UpdateGameObjectInfo(false, true); - } - catch (Exception ex) - { - ExplorerCore.LogWarning($"Exception setting tag! {ex.ReflectionExToString()}"); - } - } - - private void OnExploreButtonClicked() - { - ObjectExplorerPanel panel = UIManager.GetPanel(UIManager.Panels.ObjectExplorer); - panel.SceneExplorer.JumpToTransform(this.Parent.GOTarget.transform); - } - - private void OnLayerDropdownChanged(int value) - { - GOTarget.layer = value; - UpdateGameObjectInfo(false, true); - } - - private void OnFlagsDropdownChanged(int value) - { - try - { - HideFlags enumVal = hideFlagsValues[FlagsDropdown.options[value].text]; - GOTarget.hideFlags = enumVal; - - UpdateGameObjectInfo(false, true); - } - catch (Exception ex) - { - ExplorerCore.LogWarning($"Exception setting hideFlags: {ex}"); - } - } - - private void OnDestroyClicked() - { - GameObject.Destroy(this.GOTarget); - InspectorManager.ReleaseInspector(Parent); - } - - private void OnInstantiateClicked() - { - GameObject clone = GameObject.Instantiate(this.GOTarget); - InspectorManager.Inspect(clone); - } - - #endregion - - - #region Transform Controls - - private enum TransformType { Position, LocalPosition, Rotation, Scale } - - private class TransformControl - { - public TransformType Type; - public InputFieldRef Input; - - public TransformControl(TransformType type, InputFieldRef input) - { - this.Type = type; - this.Input = input; - } - } - - private class VectorSlider - { - public int axis; - public Slider slider; - public TransformControl parentControl; - - public VectorSlider(int axis, Slider slider, TransformControl parentControl) - { - this.axis = axis; - this.slider = slider; - this.parentControl = parentControl; - } - } - - private Vector3 lastPosValue; - private Vector3 lastLocalValue; - private Quaternion lastRotValue; - private Vector3 lastScaleValue; - - public void UpdateTransformControlValues(bool force) - { - Transform transform = GOTarget.transform; - if (force || (!PositionControl.Input.Component.isFocused && lastPosValue != transform.position)) - { - PositionControl.Input.Text = ParseUtility.ToStringForInput(transform.position, typeof(Vector3)); - lastPosValue = transform.position; - } - if (force || (!LocalPositionControl.Input.Component.isFocused && lastLocalValue != transform.localPosition)) - { - LocalPositionControl.Input.Text = ParseUtility.ToStringForInput(transform.localPosition, typeof(Vector3)); - lastLocalValue = transform.localPosition; - } - if (force || (!RotationControl.Input.Component.isFocused && lastRotValue != transform.localRotation)) - { - RotationControl.Input.Text = ParseUtility.ToStringForInput(transform.localRotation, typeof(Quaternion)); - lastRotValue = transform.localRotation; - } - if (force || (!ScaleControl.Input.Component.isFocused && lastScaleValue != transform.localScale)) - { - ScaleControl.Input.Text = ParseUtility.ToStringForInput(transform.localScale, typeof(Vector3)); - lastScaleValue = transform.localScale; - } - } - - private void OnTransformInputEndEdit(TransformType type, string input) - { - switch (type) - { - case TransformType.Position: - { - if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _)) - GOTarget.transform.position = (Vector3)boxed; - } - break; - case TransformType.LocalPosition: - { - if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _)) - GOTarget.transform.localPosition = (Vector3)boxed; - } - break; - case TransformType.Rotation: - { - if (ParseUtility.TryParse(input, typeof(Quaternion), out object boxed, out _)) - GOTarget.transform.localRotation = (Quaternion)boxed; - } - break; - case TransformType.Scale: - { - if (ParseUtility.TryParse(input, typeof(Vector3), out object boxed, out _)) - GOTarget.transform.localScale = (Vector3)boxed; - } - break; - } - - UpdateTransformControlValues(true); - } - - private void OnVectorSliderChanged(VectorSlider slider, float value) - { - if (value == 0f) - { - currentSlidingVectorControl = null; - } - else - { - currentSlidingVectorControl = slider; - currentVectorValue = value; - } - } - - public void UpdateVectorSlider() - { - if (currentSlidingVectorControl == null) - return; - - if (!InputManager.GetMouseButton(0)) - { - currentSlidingVectorControl.slider.value = 0f; - currentSlidingVectorControl = null; - currentVectorValue = 0f; - return; - } - - Transform transform = GOTarget.transform; - - Vector3 vector = Vector2.zero; - switch (currentSlidingVectorControl.parentControl.Type) - { - case TransformType.Position: - vector = transform.position; break; - case TransformType.LocalPosition: - vector = transform.localPosition; break; - case TransformType.Rotation: - vector = transform.eulerAngles; break; - case TransformType.Scale: - vector = transform.localScale; break; - } - - // apply vector value change - switch (currentSlidingVectorControl.axis) - { - case 0: - vector.x += currentVectorValue; break; - case 1: - vector.y += currentVectorValue; break; - case 2: - vector.z += currentVectorValue; break; - } - - // set vector back to transform - switch (currentSlidingVectorControl.parentControl.Type) - { - case TransformType.Position: - transform.position = vector; break; - case TransformType.LocalPosition: - transform.localPosition = vector; break; - case TransformType.Rotation: - transform.eulerAngles = vector; break; - case TransformType.Scale: - transform.localScale = vector; break; - } - - UpdateTransformControlValues(false); - } - - #endregion - - - #region GO Controls UI Construction - - private void ConstructTopInfo() - { - GameObject topInfoHolder = UIFactory.CreateVerticalGroup(Parent.Content, "TopInfoHolder", false, false, true, true, 3, - new Vector4(3, 3, 3, 3), new Color(0.1f, 0.1f, 0.1f), TextAnchor.MiddleLeft); - UIFactory.SetLayoutElement(topInfoHolder, minHeight: 100, flexibleWidth: 9999); - topInfoHolder.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; - - // first row (parent, path) - - GameObject firstRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); - UIFactory.SetLayoutGroup(firstRow, false, false, true, true, 5, 0, 0, 0, 0, default); - UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 9999); - - ViewParentButton = UIFactory.CreateButton(firstRow, "ViewParentButton", "◄ View Parent", new Color(0.2f, 0.2f, 0.2f)); - ViewParentButton.ButtonText.fontSize = 13; - UIFactory.SetLayoutElement(ViewParentButton.Component.gameObject, minHeight: 25, minWidth: 100); - ViewParentButton.OnClick += OnViewParentClicked; - - this.PathInput = UIFactory.CreateInputField(firstRow, "PathInput", "..."); - PathInput.Component.textComponent.color = Color.grey; - PathInput.Component.textComponent.fontSize = 14; - UIFactory.SetLayoutElement(PathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999); - PathInput.Component.lineType = InputField.LineType.MultiLineSubmit; - - ButtonRef 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); }; - - PathInput.Component.GetOnEndEdit().AddListener((string val) => { OnPathEndEdit(val); }); - - // Title and update row - - GameObject titleRow = UIFactory.CreateUIObject("TitleRow", topInfoHolder); - UIFactory.SetLayoutGroup(titleRow, false, false, true, true, 5); - - Text titleLabel = UIFactory.CreateLabel(titleRow, "Title", SignatureHighlighter.Parse(typeof(GameObject), false), - TextAnchor.MiddleLeft, fontSize: 17); - UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, minWidth: 100); - - // name - - NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled"); - UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999); - NameInput.Component.textComponent.fontSize = 15; - NameInput.Component.GetOnEndEdit().AddListener((string val) => { OnNameEndEdit(val); }); - - // second row (toggles, instanceID, tag, buttons) - - GameObject secondRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); - UIFactory.SetLayoutGroup(secondRow, false, false, true, true, 5, 0, 0, 0, 0, default); - UIFactory.SetLayoutElement(secondRow, minHeight: 25, flexibleWidth: 9999); - - // activeSelf - GameObject activeToggleObj = UIFactory.CreateToggle(secondRow, "ActiveSelf", out ActiveSelfToggle, out ActiveSelfText); - UIFactory.SetLayoutElement(activeToggleObj, minHeight: 25, minWidth: 100); - ActiveSelfText.text = "ActiveSelf"; - ActiveSelfToggle.onValueChanged.AddListener(OnActiveSelfToggled); - - // isStatic - GameObject isStaticObj = UIFactory.CreateToggle(secondRow, "IsStatic", out IsStaticToggle, out Text staticText); - UIFactory.SetLayoutElement(isStaticObj, minHeight: 25, minWidth: 80); - staticText.text = "IsStatic"; - staticText.color = Color.grey; - IsStaticToggle.interactable = false; - - // InstanceID - Text instanceIdLabel = UIFactory.CreateLabel(secondRow, "InstanceIDLabel", "Instance ID:", TextAnchor.MiddleRight, Color.grey); - UIFactory.SetLayoutElement(instanceIdLabel.gameObject, minHeight: 25, minWidth: 90); - - InstanceIDInput = UIFactory.CreateInputField(secondRow, "InstanceIDInput", "error"); - UIFactory.SetLayoutElement(InstanceIDInput.Component.gameObject, minHeight: 25, minWidth: 110); - InstanceIDInput.Component.textComponent.color = Color.grey; - InstanceIDInput.Component.readOnly = true; - - //Tag - Text tagLabel = UIFactory.CreateLabel(secondRow, "TagLabel", "Tag:", TextAnchor.MiddleRight, Color.grey); - UIFactory.SetLayoutElement(tagLabel.gameObject, minHeight: 25, minWidth: 40); - - TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none"); - UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999); - TagInput.Component.textComponent.color = Color.white; - TagInput.Component.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); }); - - // Instantiate - ButtonRef instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(instantiateBtn.Component.gameObject, minHeight: 25, minWidth: 120); - instantiateBtn.OnClick += OnInstantiateClicked; - - // Destroy - ButtonRef destroyBtn = UIFactory.CreateButton(secondRow, "DestroyBtn", "Destroy", new Color(0.3f, 0.2f, 0.2f)); - UIFactory.SetLayoutElement(destroyBtn.Component.gameObject, minHeight: 25, minWidth: 80); - destroyBtn.OnClick += OnDestroyClicked; - - // third row (scene, layer, flags) - - GameObject thirdrow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); - UIFactory.SetLayoutGroup(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default); - UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999); - - // Inspect in Explorer button - ButtonRef explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f)); - UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100); - explorerBtn.ButtonText.fontSize = 12; - explorerBtn.OnClick += OnExploreButtonClicked; - - // Scene - Text sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50); - - SceneInput = UIFactory.CreateInputField(thirdrow, "SceneInput", "untitled"); - UIFactory.SetLayoutElement(SceneInput.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 999); - SceneInput.Component.readOnly = true; - SceneInput.Component.textComponent.color = new Color(0.7f, 0.7f, 0.7f); - - // Layer - Text layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey); - UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50); - - GameObject layerDrop = UIFactory.CreateDropdown(thirdrow, "LayerDropdown", out LayerDropdown, "0", 14, OnLayerDropdownChanged); - UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999); - LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen; - if (layerToNames == null) - GetLayerNames(); - foreach (string name in layerToNames) - LayerDropdown.options.Add(new Dropdown.OptionData(name)); - LayerDropdown.value = 0; - LayerDropdown.RefreshShownValue(); - - // Flags - Text flagsLabel = UIFactory.CreateLabel(thirdrow, "FlagsLabel", "Flags:", TextAnchor.MiddleRight, Color.grey); - UIFactory.SetLayoutElement(flagsLabel.gameObject, minHeight: 25, minWidth: 50); - - GameObject flagsDrop = UIFactory.CreateDropdown(thirdrow, "FlagsDropdown", out FlagsDropdown, "None", 14, OnFlagsDropdownChanged); - FlagsDropdown.captionText.color = SignatureHighlighter.EnumGreen; - UIFactory.SetLayoutElement(flagsDrop, minHeight: 25, minWidth: 135, flexibleWidth: 999); - if (hideFlagsValues == null) - GetHideFlagNames(); - foreach (string name in hideFlagsValues.Keys) - FlagsDropdown.options.Add(new Dropdown.OptionData(name)); - FlagsDropdown.value = 0; - FlagsDropdown.RefreshShownValue(); - } - - private static List layerToNames; - - private static void GetLayerNames() - { - layerToNames = new List(); - for (int i = 0; i < 32; i++) - { - string name = RuntimeHelper.LayerToName(i); - if (string.IsNullOrEmpty(name)) - name = i.ToString(); - layerToNames.Add(name); - } - } - - private static Dictionary hideFlagsValues; - - private static void GetHideFlagNames() - { - hideFlagsValues = new Dictionary(); - - Array names = Enum.GetValues(typeof(HideFlags)); - foreach (HideFlags value in names) - { - hideFlagsValues.Add(value.ToString(), value); - } - } - - #endregion - - - #region Transform Controls UI Construction - - private void ConstructTransformControls() - { - GameObject transformGroup = UIFactory.CreateVerticalGroup(Parent.Content, "TransformControls", false, false, true, true, 2, - new Vector4(2, 2, 0, 0), new Color(0.1f, 0.1f, 0.1f)); - UIFactory.SetLayoutElement(transformGroup, minHeight: 100, flexibleWidth: 9999); - //transformGroup.SetActive(false); - //var groupRect = transformGroup.GetComponent(); - //groupRect.anchorMin = new Vector2(0, 1); - //groupRect.anchorMax = new Vector2(1, 1); - //groupRect.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, 0, 100); - - PositionControl = AddTransformRow(transformGroup, "Position:", TransformType.Position); - LocalPositionControl = AddTransformRow(transformGroup, "Local Position:", TransformType.LocalPosition); - RotationControl = AddTransformRow(transformGroup, "Rotation:", TransformType.Rotation); - ScaleControl = AddTransformRow(transformGroup, "Scale:", TransformType.Scale); - } - - private TransformControl AddTransformRow(GameObject transformGroup, string title, TransformType type) - { - GameObject rowObj = UIFactory.CreateUIObject("Row_" + title, transformGroup); - UIFactory.SetLayoutGroup(rowObj, false, false, true, true, 5, 0, 0, 0, 0, default); - UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 9999); - - Text titleLabel = UIFactory.CreateLabel(rowObj, "PositionLabel", title, TextAnchor.MiddleRight, Color.grey); - UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 25, minWidth: 110); - - InputFieldRef inputField = UIFactory.CreateInputField(rowObj, "InputField", "..."); - UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999); - - inputField.Component.GetOnEndEdit().AddListener((string value) => { OnTransformInputEndEdit(type, value); }); - - TransformControl control = new(type, inputField); - - AddVectorAxisSlider(rowObj, "X", 0, control); - AddVectorAxisSlider(rowObj, "Y", 1, control); - AddVectorAxisSlider(rowObj, "Z", 2, control); - - return control; - } - - private VectorSlider AddVectorAxisSlider(GameObject parent, string title, int axis, TransformControl control) - { - Text label = UIFactory.CreateLabel(parent, "Label_" + title, title + ":", TextAnchor.MiddleRight, Color.grey); - UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 30); - - GameObject sliderObj = UIFactory.CreateSlider(parent, "Slider_" + title, out Slider slider); - UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 120, flexibleWidth: 0); - slider.m_FillImage.color = Color.clear; - - slider.minValue = -1; - slider.maxValue = 1; - VectorSlider sliderControl = new(axis, slider, control); - - slider.onValueChanged.AddListener((float val) => - { - OnVectorSliderChanged(sliderControl, val); - }); - - return sliderControl; - } - - #endregion - } -} diff --git a/src/UI/Widgets/GameObjects/AxisControl.cs b/src/UI/Widgets/GameObjects/AxisControl.cs new file mode 100644 index 0000000..d26b130 --- /dev/null +++ b/src/UI/Widgets/GameObjects/AxisControl.cs @@ -0,0 +1,67 @@ +using UnityEngine; +using UnityEngine.UI; +using UniverseLib.UI; +using UniverseLib.UI.Models; +using UniverseLib.Utility; + +namespace UnityExplorer.UI.Widgets +{ + // Handles the slider and +/- buttons for a specific axis of a transform property. + + public class AxisControl + { + public readonly Vector3Control parent; + + public readonly int axis; + public readonly Slider slider; + + public AxisControl(int axis, Slider slider, Vector3Control parentControl) + { + this.parent = parentControl; + this.axis = axis; + this.slider = slider; + } + + void OnVectorSliderChanged(float value) + { + parent.Owner.CurrentSlidingAxisControl = value == 0f ? null : this; + } + + void OnVectorMinusClicked() + { + parent.Owner.AxisControlOperation(-this.parent.Increment, this.parent, this.axis); + } + + void OnVectorPlusClicked() + { + parent.Owner.AxisControlOperation(this.parent.Increment, this.parent, this.axis); + } + + public static AxisControl Create(GameObject parent, string title, int axis, Vector3Control owner) + { + Text label = UIFactory.CreateLabel(parent, $"Label_{title}", $"{title}:", TextAnchor.MiddleRight, Color.grey); + UIFactory.SetLayoutElement(label.gameObject, minHeight: 25, minWidth: 30); + + GameObject sliderObj = UIFactory.CreateSlider(parent, $"Slider_{title}", out Slider slider); + UIFactory.SetLayoutElement(sliderObj, minHeight: 25, minWidth: 75, flexibleWidth: 0); + slider.m_FillImage.color = Color.clear; + + slider.minValue = -0.1f; + slider.maxValue = 0.1f; + + AxisControl sliderControl = new(axis, slider, owner); + + slider.onValueChanged.AddListener(sliderControl.OnVectorSliderChanged); + + ButtonRef minusButton = UIFactory.CreateButton(parent, "MinusIncrementButton", "-"); + UIFactory.SetLayoutElement(minusButton.GameObject, minWidth: 20, flexibleWidth: 0, minHeight: 25); + minusButton.OnClick += sliderControl.OnVectorMinusClicked; + + ButtonRef plusButton = UIFactory.CreateButton(parent, "PlusIncrementButton", "+"); + UIFactory.SetLayoutElement(plusButton.GameObject, minWidth: 20, flexibleWidth: 0, minHeight: 25); + plusButton.OnClick += sliderControl.OnVectorPlusClicked; + + return sliderControl; + } + } +} diff --git a/src/Inspectors/GameObjectWidgets/ComponentCell.cs b/src/UI/Widgets/GameObjects/ComponentCell.cs similarity index 98% rename from src/Inspectors/GameObjectWidgets/ComponentCell.cs rename to src/UI/Widgets/GameObjects/ComponentCell.cs index ed5dd11..bb3e96a 100644 --- a/src/Inspectors/GameObjectWidgets/ComponentCell.cs +++ b/src/UI/Widgets/GameObjects/ComponentCell.cs @@ -6,7 +6,7 @@ using UniverseLib.UI.Models; using UniverseLib.UI.Widgets.ButtonList; using UniverseLib; -namespace UnityExplorer.Inspectors +namespace UnityExplorer.UI.Widgets { public class ComponentCell : ButtonCell { diff --git a/src/Inspectors/GameObjectWidgets/ComponentList.cs b/src/UI/Widgets/GameObjects/ComponentList.cs similarity index 98% rename from src/Inspectors/GameObjectWidgets/ComponentList.cs rename to src/UI/Widgets/GameObjects/ComponentList.cs index 83dc86f..3b49278 100644 --- a/src/Inspectors/GameObjectWidgets/ComponentList.cs +++ b/src/UI/Widgets/GameObjects/ComponentList.cs @@ -1,12 +1,13 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityExplorer.Inspectors; using UniverseLib; using UniverseLib.UI.Widgets.ButtonList; using UniverseLib.UI.Widgets.ScrollView; using UniverseLib.Utility; -namespace UnityExplorer.Inspectors +namespace UnityExplorer.UI.Widgets { public class ComponentList : ButtonListHandler { diff --git a/src/UI/Widgets/GameObjects/GameObjectControls.cs b/src/UI/Widgets/GameObjects/GameObjectControls.cs new file mode 100644 index 0000000..278430e --- /dev/null +++ b/src/UI/Widgets/GameObjects/GameObjectControls.cs @@ -0,0 +1,35 @@ +using UnityEngine; +using UnityExplorer.Inspectors; + +namespace UnityExplorer.UI.Widgets +{ + // The base wrapper to hold a reference to the parent Inspector and the GameObjectInfo and TransformControls widgets. + + public class GameObjectControls + { + public GameObjectInspector Parent { get; } + public GameObject Target => Parent.Target; + + public GameObjectInfoPanel GameObjectInfo { get; } + + public TransformControls TransformControl { get; } + + public GameObjectControls(GameObjectInspector parent) + { + this.Parent = parent; + + this.GameObjectInfo = new(this); + this.TransformControl = new(this); + } + + public void UpdateGameObjectInfo(bool firstUpdate, bool force) + { + GameObjectInfo.UpdateGameObjectInfo(firstUpdate, force); + } + + public void UpdateVectorSlider() + { + TransformControl.UpdateVectorSlider(); + } + } +} diff --git a/src/UI/Widgets/GameObjects/GameObjectInfoPanel.cs b/src/UI/Widgets/GameObjects/GameObjectInfoPanel.cs new file mode 100644 index 0000000..6676004 --- /dev/null +++ b/src/UI/Widgets/GameObjects/GameObjectInfoPanel.cs @@ -0,0 +1,450 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.UI; +using UnityExplorer.UI.Panels; +using UniverseLib; +using UniverseLib.UI; +using UniverseLib.UI.Models; +using UniverseLib.Utility; + +namespace UnityExplorer.UI.Widgets +{ + public class GameObjectInfoPanel + { + public GameObjectControls Owner { get; } + GameObject Target => Owner.Target; + + string lastGoName; + string lastPath; + bool lastParentState; + int lastSceneHandle; + string lastTag; + int lastLayer; + int lastFlags; + + ButtonRef ViewParentButton; + InputFieldRef PathInput; + + InputFieldRef NameInput; + Toggle ActiveSelfToggle; + Text ActiveSelfText; + Toggle IsStaticToggle; + + InputFieldRef SceneInput; + InputFieldRef InstanceIDInput; + InputFieldRef TagInput; + + Dropdown LayerDropdown; + Dropdown FlagsDropdown; + + public GameObjectInfoPanel(GameObjectControls owner) + { + this.Owner = owner; + Create(); + } + + public void UpdateGameObjectInfo(bool firstUpdate, bool force) + { + if (firstUpdate) + { + InstanceIDInput.Text = Target.GetInstanceID().ToString(); + } + + if (force || (!NameInput.Component.isFocused && Target.name != lastGoName)) + { + lastGoName = Target.name; + Owner.Parent.Tab.TabText.text = $"[G] {Target.name}"; + NameInput.Text = Target.name; + } + + if (force || !PathInput.Component.isFocused) + { + string path = Target.transform.GetTransformPath(); + if (path != lastPath) + { + lastPath = path; + PathInput.Text = path; + } + } + + if (force || Target.transform.parent != lastParentState) + { + lastParentState = Target.transform.parent; + ViewParentButton.Component.interactable = lastParentState; + if (lastParentState) + { + ViewParentButton.ButtonText.color = Color.white; + ViewParentButton.ButtonText.text = "◄ View Parent"; + } + else + { + ViewParentButton.ButtonText.color = Color.grey; + ViewParentButton.ButtonText.text = "No parent"; + } + } + + if (force || Target.activeSelf != ActiveSelfToggle.isOn) + { + ActiveSelfToggle.Set(Target.activeSelf, false); + ActiveSelfText.color = ActiveSelfToggle.isOn ? Color.green : Color.red; + } + + if (force || Target.isStatic != IsStaticToggle.isOn) + { + IsStaticToggle.Set(Target.isStatic, false); + } + + if (force || Target.scene.handle != lastSceneHandle) + { + lastSceneHandle = Target.scene.handle; + SceneInput.Text = Target.scene.IsValid() ? Target.scene.name : "None (Asset/Resource)"; + } + + if (force || (!TagInput.Component.isFocused && Target.tag != lastTag)) + { + lastTag = Target.tag; + TagInput.Text = lastTag; + } + + if (force || (Target.layer != lastLayer)) + { + lastLayer = Target.layer; + LayerDropdown.value = Target.layer; + } + + if (force || ((int)Target.hideFlags != lastFlags)) + { + lastFlags = (int)Target.hideFlags; + FlagsDropdown.captionText.text = Target.hideFlags.ToString(); + } + } + + void DoSetParent(Transform transform) + { + ExplorerCore.Log($"Setting target's transform parent to: {(transform == null ? "null" : $"'{transform.name}'")}"); + + if (Target.GetComponent()) + Target.transform.SetParent(transform, false); + else + Target.transform.parent = transform; + + UpdateGameObjectInfo(false, false); + + Owner.TransformControl.UpdateTransformControlValues(false); + } + + + #region UI event listeners + + void OnViewParentClicked() + { + if (this.Target && this.Target.transform.parent) + { + Owner.Parent.OnTransformCellClicked(this.Target.transform.parent.gameObject); + } + } + + void OnPathEndEdit(string input) + { + lastPath = input; + + if (string.IsNullOrEmpty(input)) + { + DoSetParent(null); + } + else + { + Transform parentToSet = null; + + if (input.EndsWith("/")) + input = input.Remove(input.Length - 1); + + // try the easy way + if (GameObject.Find(input) is GameObject found) + { + parentToSet = found.transform; + } + else + { + // look for inactive objects + string name = input.Split('/').Last(); + UnityEngine.Object[] allObjects = RuntimeHelper.FindObjectsOfTypeAll(typeof(GameObject)); + List shortList = new(); + foreach (UnityEngine.Object obj in allObjects) + if (obj.name == name) shortList.Add(obj.TryCast()); + foreach (GameObject go in shortList) + { + string path = go.transform.GetTransformPath(true); + if (path.EndsWith("/")) + path = path.Remove(path.Length - 1); + if (path == input) + { + parentToSet = go.transform; + break; + } + } + } + + if (parentToSet) + DoSetParent(parentToSet); + else + { + ExplorerCore.LogWarning($"Could not find any GameObject name or path '{input}'!"); + UpdateGameObjectInfo(false, true); + } + } + + } + + void OnNameEndEdit(string value) + { + Target.name = value; + UpdateGameObjectInfo(false, true); + } + + void OnCopyClicked() + { + ClipboardPanel.Copy(this.Target); + } + + void OnActiveSelfToggled(bool value) + { + Target.SetActive(value); + UpdateGameObjectInfo(false, true); + } + + void OnTagEndEdit(string value) + { + try + { + Target.tag = value; + UpdateGameObjectInfo(false, true); + } + catch (Exception ex) + { + ExplorerCore.LogWarning($"Exception setting tag! {ex.ReflectionExToString()}"); + } + } + + void OnExploreButtonClicked() + { + ObjectExplorerPanel panel = UIManager.GetPanel(UIManager.Panels.ObjectExplorer); + panel.SceneExplorer.JumpToTransform(this.Owner.Parent.Target.transform); + } + + void OnLayerDropdownChanged(int value) + { + Target.layer = value; + UpdateGameObjectInfo(false, true); + } + + void OnFlagsDropdownChanged(int value) + { + try + { + HideFlags enumVal = hideFlagsValues[FlagsDropdown.options[value].text]; + Target.hideFlags = enumVal; + + UpdateGameObjectInfo(false, true); + } + catch (Exception ex) + { + ExplorerCore.LogWarning($"Exception setting hideFlags: {ex}"); + } + } + + void OnDestroyClicked() + { + GameObject.Destroy(this.Target); + InspectorManager.ReleaseInspector(Owner.Parent); + } + + void OnInstantiateClicked() + { + GameObject clone = GameObject.Instantiate(this.Target); + InspectorManager.Inspect(clone); + } + + #endregion + + + #region UI Construction + + public void Create() + { + GameObject topInfoHolder = UIFactory.CreateVerticalGroup(Owner.Parent.Content, "TopInfoHolder", false, false, true, true, 3, + new Vector4(3, 3, 3, 3), new Color(0.1f, 0.1f, 0.1f), TextAnchor.MiddleLeft); + UIFactory.SetLayoutElement(topInfoHolder, minHeight: 100, flexibleWidth: 9999); + topInfoHolder.AddComponent().verticalFit = ContentSizeFitter.FitMode.PreferredSize; + + // first row (parent, path) + + GameObject firstRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); + UIFactory.SetLayoutGroup(firstRow, false, false, true, true, 5, 0, 0, 0, 0, default); + UIFactory.SetLayoutElement(firstRow, minHeight: 25, flexibleWidth: 9999); + + ViewParentButton = UIFactory.CreateButton(firstRow, "ViewParentButton", "◄ View Parent", new Color(0.2f, 0.2f, 0.2f)); + ViewParentButton.ButtonText.fontSize = 13; + UIFactory.SetLayoutElement(ViewParentButton.Component.gameObject, minHeight: 25, minWidth: 100); + ViewParentButton.OnClick += OnViewParentClicked; + + this.PathInput = UIFactory.CreateInputField(firstRow, "PathInput", "..."); + PathInput.Component.textComponent.color = Color.grey; + PathInput.Component.textComponent.fontSize = 14; + UIFactory.SetLayoutElement(PathInput.UIRoot, minHeight: 25, minWidth: 100, flexibleWidth: 9999); + PathInput.Component.lineType = InputField.LineType.MultiLineSubmit; + + ButtonRef 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; + + PathInput.Component.GetOnEndEdit().AddListener((string val) => { OnPathEndEdit(val); }); + + // Title and update row + + GameObject titleRow = UIFactory.CreateUIObject("TitleRow", topInfoHolder); + UIFactory.SetLayoutGroup(titleRow, false, false, true, true, 5); + + Text titleLabel = UIFactory.CreateLabel(titleRow, "Title", SignatureHighlighter.Parse(typeof(GameObject), false), + TextAnchor.MiddleLeft, fontSize: 17); + UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 30, minWidth: 100); + + // name + + NameInput = UIFactory.CreateInputField(titleRow, "NameInput", "untitled"); + UIFactory.SetLayoutElement(NameInput.Component.gameObject, minHeight: 30, minWidth: 100, flexibleWidth: 9999); + NameInput.Component.textComponent.fontSize = 15; + NameInput.Component.GetOnEndEdit().AddListener((string val) => { OnNameEndEdit(val); }); + + // second row (toggles, instanceID, tag, buttons) + + GameObject secondRow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); + UIFactory.SetLayoutGroup(secondRow, false, false, true, true, 5, 0, 0, 0, 0, default); + UIFactory.SetLayoutElement(secondRow, minHeight: 25, flexibleWidth: 9999); + + // activeSelf + GameObject activeToggleObj = UIFactory.CreateToggle(secondRow, "ActiveSelf", out ActiveSelfToggle, out ActiveSelfText); + UIFactory.SetLayoutElement(activeToggleObj, minHeight: 25, minWidth: 100); + ActiveSelfText.text = "ActiveSelf"; + ActiveSelfToggle.onValueChanged.AddListener(OnActiveSelfToggled); + + // isStatic + GameObject isStaticObj = UIFactory.CreateToggle(secondRow, "IsStatic", out IsStaticToggle, out Text staticText); + UIFactory.SetLayoutElement(isStaticObj, minHeight: 25, minWidth: 80); + staticText.text = "IsStatic"; + staticText.color = Color.grey; + IsStaticToggle.interactable = false; + + // InstanceID + Text instanceIdLabel = UIFactory.CreateLabel(secondRow, "InstanceIDLabel", "Instance ID:", TextAnchor.MiddleRight, Color.grey); + UIFactory.SetLayoutElement(instanceIdLabel.gameObject, minHeight: 25, minWidth: 90); + + InstanceIDInput = UIFactory.CreateInputField(secondRow, "InstanceIDInput", "error"); + UIFactory.SetLayoutElement(InstanceIDInput.Component.gameObject, minHeight: 25, minWidth: 110); + InstanceIDInput.Component.textComponent.color = Color.grey; + InstanceIDInput.Component.readOnly = true; + + //Tag + Text tagLabel = UIFactory.CreateLabel(secondRow, "TagLabel", "Tag:", TextAnchor.MiddleRight, Color.grey); + UIFactory.SetLayoutElement(tagLabel.gameObject, minHeight: 25, minWidth: 40); + + TagInput = UIFactory.CreateInputField(secondRow, "TagInput", "none"); + UIFactory.SetLayoutElement(TagInput.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999); + TagInput.Component.textComponent.color = Color.white; + TagInput.Component.GetOnEndEdit().AddListener((string val) => { OnTagEndEdit(val); }); + + // Instantiate + ButtonRef instantiateBtn = UIFactory.CreateButton(secondRow, "InstantiateBtn", "Instantiate", new Color(0.2f, 0.2f, 0.2f)); + UIFactory.SetLayoutElement(instantiateBtn.Component.gameObject, minHeight: 25, minWidth: 120); + instantiateBtn.OnClick += OnInstantiateClicked; + + // Destroy + ButtonRef destroyBtn = UIFactory.CreateButton(secondRow, "DestroyBtn", "Destroy", new Color(0.3f, 0.2f, 0.2f)); + UIFactory.SetLayoutElement(destroyBtn.Component.gameObject, minHeight: 25, minWidth: 80); + destroyBtn.OnClick += OnDestroyClicked; + + // third row (scene, layer, flags) + + GameObject thirdrow = UIFactory.CreateUIObject("ParentRow", topInfoHolder); + UIFactory.SetLayoutGroup(thirdrow, false, false, true, true, 5, 0, 0, 0, 0, default); + UIFactory.SetLayoutElement(thirdrow, minHeight: 25, flexibleWidth: 9999); + + // Inspect in Explorer button + ButtonRef explorerBtn = UIFactory.CreateButton(thirdrow, "ExploreBtn", "Show in Explorer", new Color(0.15f, 0.15f, 0.15f)); + UIFactory.SetLayoutElement(explorerBtn.Component.gameObject, minHeight: 25, minWidth: 100); + explorerBtn.ButtonText.fontSize = 12; + explorerBtn.OnClick += OnExploreButtonClicked; + + // Scene + Text sceneLabel = UIFactory.CreateLabel(thirdrow, "SceneLabel", "Scene:", TextAnchor.MiddleLeft, Color.grey); + UIFactory.SetLayoutElement(sceneLabel.gameObject, minHeight: 25, minWidth: 50); + + SceneInput = UIFactory.CreateInputField(thirdrow, "SceneInput", "untitled"); + UIFactory.SetLayoutElement(SceneInput.Component.gameObject, minHeight: 25, minWidth: 120, flexibleWidth: 999); + SceneInput.Component.readOnly = true; + SceneInput.Component.textComponent.color = new Color(0.7f, 0.7f, 0.7f); + + // Layer + Text layerLabel = UIFactory.CreateLabel(thirdrow, "LayerLabel", "Layer:", TextAnchor.MiddleLeft, Color.grey); + UIFactory.SetLayoutElement(layerLabel.gameObject, minHeight: 25, minWidth: 50); + + GameObject layerDrop = UIFactory.CreateDropdown(thirdrow, "LayerDropdown", out LayerDropdown, "0", 14, OnLayerDropdownChanged); + UIFactory.SetLayoutElement(layerDrop, minHeight: 25, minWidth: 110, flexibleWidth: 999); + LayerDropdown.captionText.color = SignatureHighlighter.EnumGreen; + if (layerToNames == null) + GetLayerNames(); + foreach (string name in layerToNames) + LayerDropdown.options.Add(new Dropdown.OptionData(name)); + LayerDropdown.value = 0; + LayerDropdown.RefreshShownValue(); + + // Flags + Text flagsLabel = UIFactory.CreateLabel(thirdrow, "FlagsLabel", "Flags:", TextAnchor.MiddleRight, Color.grey); + UIFactory.SetLayoutElement(flagsLabel.gameObject, minHeight: 25, minWidth: 50); + + GameObject flagsDrop = UIFactory.CreateDropdown(thirdrow, "FlagsDropdown", out FlagsDropdown, "None", 14, OnFlagsDropdownChanged); + FlagsDropdown.captionText.color = SignatureHighlighter.EnumGreen; + UIFactory.SetLayoutElement(flagsDrop, minHeight: 25, minWidth: 135, flexibleWidth: 999); + if (hideFlagsValues == null) + GetHideFlagNames(); + foreach (string name in hideFlagsValues.Keys) + FlagsDropdown.options.Add(new Dropdown.OptionData(name)); + FlagsDropdown.value = 0; + FlagsDropdown.RefreshShownValue(); + } + + private static List layerToNames; + + private static void GetLayerNames() + { + layerToNames = new List(); + for (int i = 0; i < 32; i++) + { + string name = RuntimeHelper.LayerToName(i); + if (string.IsNullOrEmpty(name)) + name = i.ToString(); + layerToNames.Add(name); + } + } + + private static Dictionary hideFlagsValues; + + private static void GetHideFlagNames() + { + hideFlagsValues = new Dictionary(); + + Array names = Enum.GetValues(typeof(HideFlags)); + foreach (HideFlags value in names) + { + hideFlagsValues.Add(value.ToString(), value); + } + } + + #endregion + + } +} diff --git a/src/UI/Widgets/GameObjects/TransformControls.cs b/src/UI/Widgets/GameObjects/TransformControls.cs new file mode 100644 index 0000000..a96ced4 --- /dev/null +++ b/src/UI/Widgets/GameObjects/TransformControls.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; +using UnityEngine.UI; +using UniverseLib.Input; +using UniverseLib.UI; +using UniverseLib.UI.Models; +using UniverseLib.Utility; + +namespace UnityExplorer.UI.Widgets +{ + // Handles axis change operations and holds references to the Vector3Controls for each transform property + + public class TransformControls + { + public GameObjectControls Owner { get; } + GameObject Target => Owner.Target; + + public AxisControl CurrentSlidingAxisControl { get; set; } + + Vector3Control PositionControl; + Vector3Control LocalPositionControl; + Vector3Control RotationControl; + Vector3Control ScaleControl; + + public TransformControls(GameObjectControls owner) + { + this.Owner = owner; + Create(); + } + + public void UpdateTransformControlValues(bool force) + { + PositionControl.Update(force); + LocalPositionControl.Update(force); + RotationControl.Update(force); + ScaleControl.Update(force); + } + + public void UpdateVectorSlider() + { + AxisControl control = CurrentSlidingAxisControl; + + if (control == null) + return; + + if (!InputManager.GetMouseButton(0)) + { + control.slider.value = 0f; + control = null; + return; + } + + AxisControlOperation(control.slider.value, control.parent, control.axis); + } + + public void AxisControlOperation(float value, Vector3Control parent, int axis) + { + Transform transform = Target.transform; + + Vector3 vector = parent.Type switch + { + TransformType.Position => transform.position, + TransformType.LocalPosition => transform.localPosition, + TransformType.Rotation => transform.localEulerAngles, + TransformType.Scale => transform.localScale, + _ => throw new NotImplementedException() + }; + + // apply vector value change + switch (axis) + { + case 0: + vector.x += value; break; + case 1: + vector.y += value; break; + case 2: + vector.z += value; break; + } + + // set vector back to transform + switch (parent.Type) + { + case TransformType.Position: + transform.position = vector; break; + case TransformType.LocalPosition: + transform.localPosition = vector; break; + case TransformType.Rotation: + transform.localEulerAngles = vector; break; + case TransformType.Scale: + transform.localScale = vector; break; + } + + UpdateTransformControlValues(false); + } + + public void Create() + { + GameObject transformGroup = UIFactory.CreateVerticalGroup(Owner.Parent.Content, "TransformControls", false, false, true, true, 2, + new Vector4(2, 2, 0, 0), new Color(0.1f, 0.1f, 0.1f)); + UIFactory.SetLayoutElement(transformGroup, minHeight: 100, flexibleWidth: 9999); + + PositionControl = Vector3Control.Create(this, transformGroup, "Position:", TransformType.Position); + LocalPositionControl = Vector3Control.Create(this, transformGroup, "Local Position:", TransformType.LocalPosition); + RotationControl = Vector3Control.Create(this, transformGroup, "Rotation:", TransformType.Rotation); + ScaleControl = Vector3Control.Create(this, transformGroup, "Scale:", TransformType.Scale); + } + } +} diff --git a/src/UI/Widgets/GameObjects/TransformType.cs b/src/UI/Widgets/GameObjects/TransformType.cs new file mode 100644 index 0000000..cba543c --- /dev/null +++ b/src/UI/Widgets/GameObjects/TransformType.cs @@ -0,0 +1,4 @@ +namespace UnityExplorer.UI.Widgets +{ + public enum TransformType { Position, LocalPosition, Rotation, Scale } +} diff --git a/src/UI/Widgets/GameObjects/Vector3Control.cs b/src/UI/Widgets/GameObjects/Vector3Control.cs new file mode 100644 index 0000000..2702d3f --- /dev/null +++ b/src/UI/Widgets/GameObjects/Vector3Control.cs @@ -0,0 +1,130 @@ +using System; +using UnityEngine; +using UnityEngine.UI; +using UniverseLib.UI; +using UniverseLib.UI.Models; +using UniverseLib.Utility; + +namespace UnityExplorer.UI.Widgets +{ + // Controls a Vector3 property of a Transform, and holds references to each AxisControl for X/Y/Z. + + public class Vector3Control + { + public TransformControls Owner { get; } + public GameObject Target => Owner.Owner.Target; + public Transform Transform => Target.transform; + public TransformType Type { get; } + + public InputFieldRef MainInput { get; } + + public AxisControl[] AxisControls { get; } = new AxisControl[3]; + + public InputFieldRef IncrementInput { get; set; } + public float Increment { get; set; } = 0.1f; + + Vector3 lastValue; + + Vector3 CurrentValue => Type switch + { + TransformType.Position => Transform.position, + TransformType.LocalPosition => Transform.localPosition, + TransformType.Rotation => Transform.localEulerAngles, + TransformType.Scale => Transform.localScale, + _ => throw new NotImplementedException() + }; + + public Vector3Control(TransformControls owner, TransformType type, InputFieldRef input) + { + this.Owner = owner; + this.Type = type; + this.MainInput = input; + } + + public void Update(bool force) + { + Vector3 currValue = CurrentValue; + if (force || (!MainInput.Component.isFocused && !lastValue.Equals(currValue))) + { + MainInput.Text = ParseUtility.ToStringForInput(currValue); + lastValue = currValue; + } + } + + void OnTransformInputEndEdit(TransformType type, string input) + { + switch (type) + { + case TransformType.Position: + { + if (ParseUtility.TryParse(input, out Vector3 val, out _)) + Target.transform.position = val; + } + break; + case TransformType.LocalPosition: + { + if (ParseUtility.TryParse(input, out Vector3 val, out _)) + Target.transform.localPosition = val; + } + break; + case TransformType.Rotation: + { + if (ParseUtility.TryParse(input, out Vector3 val, out _)) + Target.transform.localEulerAngles = val; + } + break; + case TransformType.Scale: + { + if (ParseUtility.TryParse(input, out Vector3 val, out _)) + Target.transform.localScale = val; + } + break; + } + + Owner.UpdateTransformControlValues(true); + } + + void IncrementInput_OnEndEdit(string value) + { + if (!ParseUtility.TryParse(value, out float increment, out _)) + IncrementInput.Text = ParseUtility.ToStringForInput(Increment); + else + { + Increment = increment; + foreach (AxisControl slider in AxisControls) + { + slider.slider.minValue = -increment; + slider.slider.maxValue = increment; + } + } + } + + public static Vector3Control Create(TransformControls owner, GameObject transformGroup, string title, TransformType type) + { + GameObject rowObj = UIFactory.CreateUIObject($"Row_{title}", transformGroup); + UIFactory.SetLayoutGroup(rowObj, false, false, true, true, 5, 0, 0, 0, 0, default); + UIFactory.SetLayoutElement(rowObj, minHeight: 25, flexibleWidth: 9999); + + Text titleLabel = UIFactory.CreateLabel(rowObj, "PositionLabel", title, TextAnchor.MiddleRight, Color.grey); + UIFactory.SetLayoutElement(titleLabel.gameObject, minHeight: 25, minWidth: 110); + + InputFieldRef inputField = UIFactory.CreateInputField(rowObj, "InputField", "..."); + UIFactory.SetLayoutElement(inputField.Component.gameObject, minHeight: 25, minWidth: 100, flexibleWidth: 999); + + Vector3Control control = new(owner, type, inputField); + + inputField.Component.GetOnEndEdit().AddListener((string value) => { control.OnTransformInputEndEdit(type, value); }); + + control.AxisControls[0] = AxisControl.Create(rowObj, "X", 0, control); + control.AxisControls[1] = AxisControl.Create(rowObj, "Y", 1, control); + control.AxisControls[2] = AxisControl.Create(rowObj, "Z", 2, control); + + control.IncrementInput = UIFactory.CreateInputField(rowObj, "IncrementInput", "..."); + control.IncrementInput.Text = "0.1"; + UIFactory.SetLayoutElement(control.IncrementInput.GameObject, minWidth: 30, flexibleWidth: 0, minHeight: 25); + control.IncrementInput.Component.GetOnEndEdit().AddListener(control.IncrementInput_OnEndEdit); + + return control; + } + } +}