diff --git a/.github/workflows/upm-dev.yml b/.github/workflows/upm-dev.yml new file mode 100644 index 00000000..8e3b9997 --- /dev/null +++ b/.github/workflows/upm-dev.yml @@ -0,0 +1,19 @@ +name: Update UPM branch (develop) +on: + push: + branches: + - develop +jobs: + split-upm: + name: split upm branch + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: split upm branch + run: | + git subtree split -P "$PKG_ROOT" -b upm-dev + git push -u origin upm-dev + env: + PKG_ROOT: 'Assets/Editor Toolbox' diff --git a/Assets/Editor Toolbox/CHANGELOG.md b/Assets/Editor Toolbox/CHANGELOG.md index 9a40fa3e..f5090a99 100644 --- a/Assets/Editor Toolbox/CHANGELOG.md +++ b/Assets/Editor Toolbox/CHANGELOG.md @@ -1,3 +1,15 @@ +## 0.12.3 [17.06.2023] + +### Changed: +- Fix updating SerializedScene index after deleting Scene +- Fix SerializedScene index calculation +- Fix NRE when deleted Scene was still included in Build Settings +- Fix compilation errors in Unity 2018.x + +### Added: +- SceneView extension: better way to select raycasted objects in the Scene view +- LabelWidthAttribute + ## 0.12.1 [12.04.2023] ### Changed: diff --git a/Assets/Editor Toolbox/Editor/Drawers/Regular/SerializedSceneDrawer.cs b/Assets/Editor Toolbox/Editor/Drawers/Regular/SerializedSceneDrawer.cs index 0108181b..b555f02b 100644 --- a/Assets/Editor Toolbox/Editor/Drawers/Regular/SerializedSceneDrawer.cs +++ b/Assets/Editor Toolbox/Editor/Drawers/Regular/SerializedSceneDrawer.cs @@ -51,7 +51,7 @@ protected override void OnGUISafe(Rect position, SerializedProperty property, GU return; } - var sceneData = SceneData.GetSceneData(sceneProperty); + var sceneData = SceneData.GetSceneDataFromIndex(property); var spacing = EditorGUIUtility.standardVerticalSpacing; position.y += EditorGUIUtility.singleLineHeight + spacing; if (sceneData.inBuild) @@ -82,10 +82,21 @@ private struct SceneData { public int index; public bool enabled; - public GUID guid; public bool inBuild; - public static SceneData GetSceneData(SerializedProperty property) + public static SceneData GetSceneDataFromIndex(SerializedProperty property) + { + var indexProperty = property.FindPropertyRelative("buildIndex"); + var index = indexProperty.intValue; + return new SceneData() + { + index = index, + enabled = index != -1, + inBuild = index != -1 + }; + } + + public static SceneData GetSceneDataFromScene(SerializedProperty property) { var sceneData = new SceneData() { @@ -101,7 +112,7 @@ public static SceneData GetSceneData(SerializedProperty property) for (var i = 0; i < EditorBuildSettings.scenes.Length; i++) { var sceneSettings = EditorBuildSettings.scenes[i]; - var isEnabled = sceneSettings.enabled; + var isEnabled = sceneSettings.enabled && !string.IsNullOrEmpty(sceneSettings.path); if (isEnabled) { sceneIndex++; @@ -112,7 +123,6 @@ public static SceneData GetSceneData(SerializedProperty property) { sceneData.index = isEnabled ? sceneIndex : -1; sceneData.enabled = isEnabled; - sceneData.guid = guid; sceneData.inBuild = true; break; } diff --git a/Assets/Editor Toolbox/Editor/Editors/ToolboxScriptedImporterEditor.cs b/Assets/Editor Toolbox/Editor/Editors/ToolboxScriptedImporterEditor.cs index e2dd56ed..55ae9528 100644 --- a/Assets/Editor Toolbox/Editor/Editors/ToolboxScriptedImporterEditor.cs +++ b/Assets/Editor Toolbox/Editor/Editors/ToolboxScriptedImporterEditor.cs @@ -1,5 +1,9 @@ using UnityEditor; +#if UNITY_2020_2_OR_NEWER using UnityEditor.AssetImporters; +#else +using UnityEditor.Experimental.AssetImporters; +#endif namespace Toolbox.Editor.Editors { @@ -15,11 +19,12 @@ public sealed override void OnInspectorGUI() public virtual void DrawCustomInspector() { Drawer.DrawEditor(serializedObject); +#if UNITY_2020_2_OR_NEWER if (extraDataType != null) { Drawer.DrawEditor(extraDataSerializedObject); } - +#endif ApplyRevertGUI(); } diff --git a/Assets/Editor Toolbox/Editor/SceneView.meta b/Assets/Editor Toolbox/Editor/SceneView.meta new file mode 100644 index 00000000..d2197a22 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/SceneView.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7cca29365d790494bbae22d223dc17de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs b/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs new file mode 100644 index 00000000..0f6f834e --- /dev/null +++ b/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs @@ -0,0 +1,326 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace Toolbox.Editor.SceneView +{ + public class ToolboxEditorSceneViewObjectSelector : EditorWindow + { + private static readonly Color selectionColor = new Color(0.50f, 0.70f, 1.00f); + + private const float sizeXPadding = 2f; + private const float sizeYPadding = 2f; + private const float buttonYSpacing = 0.0f; + private const float buttonYSize = 20f; + private const float sizeXOffset = -30f; + + private List gameObjects; + private List gameObjectPaths; + + private GameObject highlightedObject; + private Vector2 size; + private Vector2 buttonSize; + + private int shiftMinSelectionId = -1; + private int shiftMaxSelectionId = -1; + private int shiftLastId = -1; + + public static void Show(List gameObjects, Vector2 position) + { + var rect = new Rect(position, Vector2.one); + + var window = CreateInstance(); + window.wantsMouseMove = true; + window.wantsMouseEnterLeaveWindow = true; + window.gameObjects = gameObjects; + window.InitializeGameObjectPaths(); + window.CalculateSize(); + window.ShowAsDropDown(rect, window.size); + } + + private void OnGUI() + { + if (Event.current.type == EventType.Layout) + { + return; + } + + switch (Event.current.type) + { + case EventType.MouseMove: + OnGuiMouseMove(); + break; + case EventType.MouseLeaveWindow: + OnGuiMouseLeave(); + break; + default: + OnGuiNormal(); + break; + } + } + + private void OnGuiMouseLeave() + { + HighlightedObject = null; + } + + private void OnGuiMouseMove() + { + var rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y); + for (var i = 0; i < gameObjects.Count; i++) + { + var gameObject = gameObjects[i]; + if (gameObject == null) + { + //Can happen when something removes the gameobject during the window display. + continue; + } + + var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject)); + GUI.Button(rect, content, Style.buttonStyle); + if (rect.Contains(Event.current.mousePosition)) + { + HighlightedObject = gameObject; + } + + rect.y += buttonYSize + buttonYSpacing; + } + } + + private void OnGuiNormal() + { + var rect = new Rect(sizeXPadding, sizeYPadding, buttonSize.x, buttonSize.y); + for (var i = 0; i < gameObjects.Count; i++) + { + var gameObject = gameObjects[i]; + if (gameObject == null) + { + //Can happen when something removes the gameobject during the window display. + continue; + } + + var content = EditorGUIUtility.ObjectContent(gameObject, typeof(GameObject)); + var objectSelected = Selection.Contains(gameObject); + if (objectSelected) + { + GUI.backgroundColor = selectionColor; + } + + if (GUI.Button(rect, content, Style.buttonStyle)) + { + GameObjectButtonPress(i); + } + + GUI.backgroundColor = Color.white; + rect.y += buttonYSize + buttonYSpacing; + } + } + + private Vector2 CalculateSize() + { + size = Vector2.zero; + + foreach (var go in gameObjects) + { + var content = EditorGUIUtility.ObjectContent(go, typeof(GameObject)); + var currentSize = Style.buttonStyle.CalcSize(content); + if (currentSize.x > size.x) + { + size.x = currentSize.x; + } + } + + //This is needed because CalcSize calculates content drawing with icon at full size. + size.x += sizeXOffset; + + buttonSize.x = size.x; + buttonSize.y = buttonYSize; + + size.y = gameObjects.Count * buttonYSize + sizeYPadding * 2.0f + buttonYSpacing * gameObjects.Count - 1; + size.x += sizeXPadding * 2.0f; + + return size; + } + + private void InitializeGameObjectPaths() + { + gameObjectPaths = new List(); + var pathStack = new Stack(); + + for (var i = 0; i < gameObjects.Count; i++) + { + pathStack.Clear(); + var transform = gameObjects[i].transform; + pathStack.Push(transform.gameObject.name); + + while (transform.parent != null) + { + transform = transform.parent; + pathStack.Push(transform.gameObject.name); + } + + var path = string.Join("/", pathStack.ToArray()); + gameObjectPaths.Add(path); + } + } + + private void GameObjectButtonPress(int id) + { + SelectObject(id, Event.current.control, Event.current.shift); + if (Event.current.control || Event.current.shift) + { + return; + } + + Close(); + } + + private void UpdateShiftSelectionIDs(int id) + { + if (shiftLastId == -1) + { + shiftLastId = id; + } + + if (shiftMinSelectionId == -1) + { + shiftMinSelectionId = id; + } + + if (shiftMaxSelectionId == -1) + { + shiftMaxSelectionId = id; + } + + if (id < shiftMinSelectionId) + { + shiftMinSelectionId = id; + } + else if (id >= shiftMaxSelectionId) + { + shiftMaxSelectionId = id; + } + else if (id > shiftMinSelectionId) + { + //ID is between min and max. + if (shiftLastId < id) + { + shiftMaxSelectionId = id; + } + else + { + shiftMinSelectionId = id; + } + } + + shiftLastId = id; + } + + private void SelectObject(int id, bool control, bool shift) + { + var gameObject = gameObjects[id]; + + if (shift) + { + UpdateShiftSelectionIDs(id); + SelectObjects(shiftMinSelectionId, shiftMaxSelectionId); + } + else if (control) + { + UpdateShiftSelectionIDs(id); + if (Selection.Contains(gameObject)) + { + RemoveSelectedObject(gameObject); + } + else + { + AppendSelectedObject(gameObject); + } + } + else + { + Selection.objects = new Object[] { gameObject }; + } + } + + private void SelectObjects(int minId, int maxId) + { + var size = maxId - minId + 1; + var newSelection = new Object[size]; + + var index = 0; + + for (var i = minId; i <= maxId; i++) + { + newSelection[index] = gameObjects[i]; + index++; + } + + Selection.objects = newSelection; + } + + private void AppendSelectedObject(GameObject gameObject) + { + var currentSelection = Selection.objects; + var newSelection = new Object[currentSelection.Length + 1]; + + currentSelection.CopyTo(newSelection, 0); + newSelection[newSelection.Length - 1] = gameObject; + + Selection.objects = newSelection; + } + + private void RemoveSelectedObject(GameObject gameObject) + { + var currentSelection = Selection.objects; + var newSelection = new Object[currentSelection.Length - 1]; + + var index = 0; + + for (var i = 0; i < currentSelection.Length; i++) + { + if (currentSelection[i] == gameObject) + { + continue; + } + + newSelection[index] = currentSelection[i]; + index++; + } + + Selection.objects = newSelection; + } + + private GameObject HighlightedObject + { + set + { + if (highlightedObject == value) + { + return; + } + + highlightedObject = value; + UnityEditor.SceneView.RepaintAll(); + + if (highlightedObject != null) + { + EditorGUIUtility.PingObject(highlightedObject); + } + } + } + + private static class Style + { + internal static readonly GUIStyle buttonStyle; + + static Style() + { + buttonStyle = new GUIStyle(GUI.skin.button) + { + alignment = TextAnchor.MiddleLeft + }; + } + } + } +} \ No newline at end of file diff --git a/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs.meta b/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs.meta new file mode 100644 index 00000000..30c05240 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/SceneView/ToolboxEditorSceneViewObjectSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23e85c8e0f6e08041a82bda7b21fdea1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs b/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs new file mode 100644 index 00000000..dd1ef369 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace Toolbox.Editor +{ + using Toolbox.Editor.SceneView; + + [InitializeOnLoad] + public static class ToolboxEditorSceneView + { + static ToolboxEditorSceneView() + { + UpdateEventCallback(); + } + + private static List GetObjectsUnderCursor() + { + const int maxIterations = 50; + + var mousePosition = Event.current.mousePosition; + var hitObjects = new List(); + GameObject[] hitObjectsArray; + for (var i = 0; i < maxIterations; i++) + { + hitObjectsArray = hitObjects.ToArray(); + + var go = HandleUtility.PickGameObject(mousePosition, true, hitObjectsArray); + if (go == null) + { + break; + } + + hitObjects.Add(go); + } + + return hitObjects; + } + + private static void UpdateEventCallback() + { +#if UNITY_2019_1_OR_NEWER + UnityEditor.SceneView.duringSceneGui -= SceneViewDuringSceneGUI; + + if (UseToolboxSceneView) + { + UnityEditor.SceneView.duringSceneGui += SceneViewDuringSceneGUI; + } +#endif + } + + private static void SceneViewDuringSceneGUI(UnityEditor.SceneView sceneView) + { + if (Event.current.type != EventType.KeyDown || + Event.current.keyCode != SelectorKey) + { + return; + } + + var objectsUnderCursor = GetObjectsUnderCursor(); + if (objectsUnderCursor.Count > 0) + { + ToolboxEditorSceneViewObjectSelector.Show(objectsUnderCursor, Event.current.mousePosition + sceneView.position.position); + } + } + + internal static void UpdateSettings(IToolboxSceneViewSettings settings) + { + if (settings == null) + { + UseToolboxSceneView = true; + SelectorKey = KeyCode.LeftControl; + } + else + { + UseToolboxSceneView = settings.UseToolboxSceneView; + SelectorKey = settings.SelectorKey; + } + + UpdateEventCallback(); + } + + /// + /// Should the scene view be used. + /// + private static bool UseToolboxSceneView { get; set; } = true; + + /// + /// Which key should activate the scene view. + /// + private static KeyCode SelectorKey { get; set; } = KeyCode.LeftControl; + } +} diff --git a/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs.meta b/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs.meta new file mode 100644 index 00000000..86f8da28 --- /dev/null +++ b/Assets/Editor Toolbox/Editor/ToolboxEditorSceneView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: baf6be454a6d71f4b9ec44e48e6b0df2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Editor/ToolboxEditorSettings.cs b/Assets/Editor Toolbox/Editor/ToolboxEditorSettings.cs index 61fc1c38..c0145382 100644 --- a/Assets/Editor Toolbox/Editor/ToolboxEditorSettings.cs +++ b/Assets/Editor Toolbox/Editor/ToolboxEditorSettings.cs @@ -52,8 +52,15 @@ internal interface IToolboxInspectorSettings List TargetTypeDrawerHandlers { get; } } + internal interface IToolboxSceneViewSettings + { + bool UseToolboxSceneView { get; } + + KeyCode SelectorKey { get; } + } + [CreateAssetMenu(fileName = "Editor Toolbox Settings", menuName = "Editor Toolbox/Settings")] - internal class ToolboxEditorSettings : ScriptableObject, IToolboxGeneralSettings, IToolboxHierarchySettings, IToolboxProjectSettings, IToolboxInspectorSettings + internal class ToolboxEditorSettings : ScriptableObject, IToolboxGeneralSettings, IToolboxHierarchySettings, IToolboxProjectSettings, IToolboxInspectorSettings, IToolboxSceneViewSettings { [SerializeField] private bool useToolboxHierarchy = true; @@ -82,6 +89,12 @@ internal class ToolboxEditorSettings : ScriptableObject, IToolboxGeneralSettings [SerializeField, ReorderableList(ListStyle.Boxed)] private List customFolders = new List(); + [SerializeField] + private bool useToolboxSceneView = true; + + [SerializeField] + private KeyCode selectorKey = KeyCode.LeftControl; + [SerializeField, Tooltip("Set to false if you don't want to use Toolbox attributes and related features.")] private bool useToolboxDrawers = true; [SerializeField, Tooltip("By default, Inspectors will use the built-in version of the list instead of the Toolbox-based one. " + @@ -103,11 +116,12 @@ internal class ToolboxEditorSettings : ScriptableObject, IToolboxGeneralSettings private bool hierarchySettingsDirty; private bool projectSettingsDirty; private bool inspectorSettingsDirty; + private bool sceneViewSettingsDirty; internal event Action OnHierarchySettingsChanged; internal event Action OnProjectSettingsChanged; internal event Action OnInspectorSettingsChanged; - + internal event Action OnSceneViewSettingsChanged; #region Methods: Internal/data validation @@ -135,6 +149,13 @@ internal void SetInspectorSettingsDirty() inspectorSettingsDirty = true; } + /// + /// Forces Scene settings validation in the next call. + /// + internal void SetSceneViewSettingsDirty() + { + sceneViewSettingsDirty = true; + } internal void ValidateHierarchySettings() { @@ -151,11 +172,17 @@ internal void ValidateInspectorSettings() OnInspectorSettingsChanged?.Invoke(this); } + internal void ValidateSceneViewSettings() + { + OnSceneViewSettingsChanged?.Invoke(this); + } + internal void Validate() { ValidateHierarchySettings(); ValidateProjectSettings(); ValidateInspectorSettings(); + ValidateSceneViewSettings(); } @@ -183,6 +210,11 @@ private void OnValidate() { ValidateInspectorSettings(); } + + if (sceneViewSettingsDirty) + { + ValidateSceneViewSettings(); + } } else { @@ -206,6 +238,7 @@ public void Reset() ResetHierarchySettings(); ResetProjectSettings(); ResetInspectorSettings(); + ResetSceneSettings(); } public void ResetHierarchySettings() @@ -233,6 +266,12 @@ public void ResetInspectorSettings() SetAllPossibleTargetTypeDrawers(); } + public void ResetSceneSettings() + { + UseToolboxSceneView = true; + SelectorKey = KeyCode.LeftControl; + } + public void SetAllPossibleDecoratorDrawers() { decoratorDrawerHandlers.Clear(); @@ -355,6 +394,18 @@ public List CustomFolders set => customFolders = value; } + public bool UseToolboxSceneView + { + get => useToolboxSceneView; + set => useToolboxSceneView = value; + } + + public KeyCode SelectorKey + { + get => selectorKey; + set => selectorKey = value; + } + public bool UseToolboxDrawers { get => useToolboxDrawers; diff --git a/Assets/Editor Toolbox/Editor/ToolboxEditorSettingsEditor.cs b/Assets/Editor Toolbox/Editor/ToolboxEditorSettingsEditor.cs index f68079a2..280253de 100644 --- a/Assets/Editor Toolbox/Editor/ToolboxEditorSettingsEditor.cs +++ b/Assets/Editor Toolbox/Editor/ToolboxEditorSettingsEditor.cs @@ -18,6 +18,7 @@ internal class ToolboxEditorSettingsEditor : ToolboxEditor private AnimBool hierarchyAnimBool; private AnimBool projectAnimBool; private AnimBool inspectorAnimBool; + private AnimBool sceneViewAnimBool; private int enabledToShowDrawerType; @@ -31,6 +32,8 @@ internal class ToolboxEditorSettingsEditor : ToolboxEditor private SerializedProperty smallIconScaleProperty; private SerializedProperty largeIconPaddingProperty; private SerializedProperty smallIconPaddingProperty; + private SerializedProperty useToolboxSceneViewProperty; + private SerializedProperty selectorKeyProperty; private ReorderableListBase rowDataItemsList; private ReorderableListBase customFoldersList; @@ -50,6 +53,7 @@ private void OnEnable() hierarchyAnimBool = new AnimBool(ToolboxPrefs.GetBool(nameof(ToolboxEditorSettings), "HierarchyEnabled")); projectAnimBool = new AnimBool(ToolboxPrefs.GetBool(nameof(ToolboxEditorSettings), "ProjectEnabled")); inspectorAnimBool = new AnimBool(ToolboxPrefs.GetBool(nameof(ToolboxEditorSettings), "InspectorEnabled")); + sceneViewAnimBool = new AnimBool(ToolboxPrefs.GetBool(nameof(ToolboxEditorSettings), "SceneViewEnabled")); enabledToShowDrawerType = ToolboxPrefs.GetInt(nameof(ToolboxEditorSettings), "PickedDrawerType"); @@ -63,6 +67,7 @@ private void OnEnable() hierarchyAnimBool.valueChanged.AddListener(repaintAction); projectAnimBool.valueChanged.AddListener(repaintAction); inspectorAnimBool.valueChanged.AddListener(repaintAction); + sceneViewAnimBool.valueChanged.AddListener(repaintAction); //hierarchy-related properties useToolboxHierarchyProperty = serializedObject.FindProperty("useToolboxHierarchy"); @@ -127,6 +132,10 @@ private void OnEnable() "", "" }; + + //SceneView-related properties + useToolboxSceneViewProperty = serializedObject.FindProperty("useToolboxSceneView"); + selectorKeyProperty = serializedObject.FindProperty("selectorKey"); } private void OnDisable() @@ -334,6 +343,26 @@ private void DrawInspectorSettings() EditorGUI.indentLevel--; } + private void DrawSceneViewSettings() + { + EditorGUI.indentLevel++; + EditorGUI.BeginChangeCheck(); + EditorGUILayout.Space(); + EditorGUILayout.PropertyField(useToolboxSceneViewProperty); + EditorGUILayout.Space(); + + EditorGUI.BeginDisabledGroup(!useToolboxSceneViewProperty.boolValue); + EditorGUILayout.PropertyField(selectorKeyProperty); + EditorGUI.EndDisabledGroup(); + + if (EditorGUI.EndChangeCheck()) + { + currentTarget.SetSceneViewSettingsDirty(); + } + + EditorGUI.indentLevel--; + } + private void ApplyAllDrawers() { Undo.RecordObject(target, "Assign Drawers"); @@ -425,10 +454,20 @@ public override void DrawCustomInspector() } } + GUILayout.Space(EditorGUIUtility.standardVerticalSpacing); + //handle inspector settings section + sceneViewAnimBool.target = DrawHeaderFoldout(sceneViewAnimBool.target, Style.sceneViewSettingsContent, true, Style.sectionHeaderStyle, Style.headersGroupStyle); + using (var group = new EditorGUILayout.FadeGroupScope(sceneViewAnimBool.faded)) + { + if (group.visible) + { + DrawSceneViewSettings(); + } + } + serializedObject.ApplyModifiedProperties(); } - internal static class Style { internal static readonly GUIStyle headersGroupStyle; @@ -451,6 +490,8 @@ internal static class Style EditorGUIUtility.IconContent("Project").image); internal static readonly GUIContent inspectorSettingsContent = new GUIContent("Inspector", EditorGUIUtility.IconContent("UnityEditor.InspectorWindow").image); + internal static readonly GUIContent sceneViewSettingsContent = new GUIContent("SceneView", + EditorGUIUtility.IconContent("UnityEditor.SceneView").image); internal static readonly GUILayoutOption[] resetButtonOptions = new GUILayoutOption[] { diff --git a/Assets/Editor Toolbox/Editor/ToolboxManager.cs b/Assets/Editor Toolbox/Editor/ToolboxManager.cs index 2b327b3d..413ea350 100644 --- a/Assets/Editor Toolbox/Editor/ToolboxManager.cs +++ b/Assets/Editor Toolbox/Editor/ToolboxManager.cs @@ -12,13 +12,13 @@ internal static class ToolboxManager private static Editor globalSettingsEditor; - private static void ForceModulesUpdate() { //perform separated modules update ManageInspectorCore(Settings); ManageProjectCore(Settings); ManageHierarchyCore(Settings); + ManageSceneViewCore(Settings); } private static void ManageInspectorCore(IToolboxInspectorSettings settings) @@ -82,6 +82,11 @@ private static void ManageHierarchyCore(IToolboxHierarchySettings settings) ToolboxEditorHierarchy.RepaintHierarchyOverlay(); } + private static void ManageSceneViewCore(IToolboxSceneViewSettings settings) + { + ToolboxEditorSceneView.UpdateSettings(settings); + } + [InitializeOnLoadMethod] internal static bool InitializeSettings() @@ -122,6 +127,7 @@ internal static bool InitializeSettings(string settingsGuid) Settings.OnHierarchySettingsChanged += ManageHierarchyCore; Settings.OnProjectSettingsChanged += ManageProjectCore; Settings.OnInspectorSettingsChanged += ManageInspectorCore; + Settings.OnSceneViewSettingsChanged += ManageSceneViewCore; //initialize core functionalities Settings.Validate(); return true; diff --git a/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs b/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs index d8020a36..8f98ed0d 100644 --- a/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs +++ b/Assets/Editor Toolbox/Editor/Utilities/PropertyUtility.cs @@ -120,8 +120,13 @@ public static object GetTreePathReference(string treeField, object treeParent) } var fieldType = treeParent.GetType(); - var fieldInfo = fieldType.GetField(treeField, - BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + var fieldInfo = fieldType.GetField(treeField, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + if (fieldInfo == null) + { + ToolboxEditorLog.LogError($"Cannot find field: '{treeField}'."); + return null; + } + return fieldInfo.GetValue(treeParent); } diff --git a/Assets/Editor Toolbox/EditorSettings.asset b/Assets/Editor Toolbox/EditorSettings.asset index 3fba6090..ada24212 100644 --- a/Assets/Editor Toolbox/EditorSettings.asset +++ b/Assets/Editor Toolbox/EditorSettings.asset @@ -46,6 +46,8 @@ MonoBehaviour: largeIcon: {fileID: 2800000, guid: 6315862a85e61a44e947fbd4b1b23e11, type: 3} smallIcon: {fileID: 2800000, guid: e99d63b63394eba4aaf10385704d0ef3, type: 3} iconName: + useToolboxSceneView: 1 + selectorKey: 306 useToolboxDrawers: 1 forceDefaultLists: 0 decoratorDrawerHandlers: diff --git a/Assets/Editor Toolbox/README.md b/Assets/Editor Toolbox/README.md index 69e04a50..7aa432cb 100644 --- a/Assets/Editor Toolbox/README.md +++ b/Assets/Editor Toolbox/README.md @@ -36,7 +36,8 @@ Unity 2018.x or newer - Enable/disable Hierarchy overlay, choose allowed information - Enable/disable Project icons or/and assign own directories - Enable/disable Toolbox drawers or/and assign custom drawers - + - Enable/disable Toolbox Scene View and assign hotkeys + ## Table Of Contents - [Attributes & Drawers](#drawers) @@ -56,15 +57,17 @@ Unity 2018.x or newer - [Project](#project) - [Toolbar](#toolbar) - [Utilities](#utilities) + - [SceneView](#sceneview) ## Settings The most important file, allows the user to manage all available features. Can be accessed from the Project Settings window (Edit/Project Settings.../Editor Toolbox) or directly inside the Project window. Make sure to have one valid settings file per project. -Available features are divided into three groups: +Available features are divided into four groups: - Hierarchy - Project - Inspector +- SceneView Each module is described in its respective section. @@ -228,6 +231,15 @@ public int bigNumber; ![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/formattednumber.png) +#### LabelWidthAttribute + +```csharp +[LabelWidth(220.0f)] +public int veryVeryVeryVeryVeryLongName; +``` + +![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/labelwidth.png) + --- ### Toolbox Drawers @@ -844,3 +856,9 @@ Assets/Create/Editor Toolbox/ScriptableObject Creation Wizard ``` ![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/createso.png) + +### SceneView + +Select a specific object that is under the cursor (default key: left control). + +![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/sceneview.png) \ No newline at end of file diff --git a/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs new file mode 100644 index 00000000..be3cab5c --- /dev/null +++ b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs @@ -0,0 +1,42 @@ +using System.IO; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace Toolbox.Serialization +{ +#if UNITY_EDITOR + public class SceneSerializationProcessor : AssetPostprocessor + { +#if UNITY_2021_3_OR_NEWER + internal static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) +#else + internal static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) +#endif + { + foreach (string path in importedAssets) + { + if (IsSceneAsset(path)) + { + SceneSerializationUtility.RefreshCache(); + return; + } + } + + foreach (string path in deletedAssets) + { + if (IsSceneAsset(path)) + { + SceneSerializationUtility.RefreshCache(); + return; + } + } + } + + private static bool IsSceneAsset(string path) + { + return Path.GetExtension(path) == ".unity"; + } + } +#endif +} \ No newline at end of file diff --git a/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs.meta b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs.meta new file mode 100644 index 00000000..509323f9 --- /dev/null +++ b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10115db7d10ebb44bb574a68e78b333d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationUtility.cs b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationUtility.cs index 23512cc7..0fc087e4 100644 --- a/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationUtility.cs +++ b/Assets/Editor Toolbox/Runtime/Serialization/SceneSerializationUtility.cs @@ -27,7 +27,7 @@ private static void Initialize() isInitialized = true; } - private static void ConfirmCache() + internal static void ConfirmCache() { //NOTE: refresh data only if the cache is empty, //it probably means that it's our first time when we are updating it @@ -37,7 +37,7 @@ private static void ConfirmCache() } } - private static void RefreshCache() + internal static void RefreshCache() { cachedScenes.Clear(); var buildIndex = -1; @@ -47,25 +47,31 @@ private static void RefreshCache() { continue; } - - buildIndex++; - var sceneIndex = scene.enabled ? buildIndex : InvalidSceneIndex; var sceneAsset = EditorGUIUtility.Load(scene.path) as SceneAsset; - if (sceneAsset != null) + if (sceneAsset == null) { - if (cachedScenes.ContainsKey(sceneAsset)) - { - continue; - } - - cachedScenes.Add(sceneAsset, new SceneData() - { - BuildIndex = buildIndex, - SceneName = sceneAsset.name, - ScenePath = scene.path - }); + continue; + } + + var sceneIndex = InvalidSceneIndex; + if (scene.enabled) + { + buildIndex++; + sceneIndex = buildIndex; + } + + if (cachedScenes.ContainsKey(sceneAsset)) + { + continue; } + + cachedScenes.Add(sceneAsset, new SceneData() + { + BuildIndex = sceneIndex, + SceneName = sceneAsset.name, + ScenePath = scene.path + }); } } @@ -86,4 +92,4 @@ public static bool TryGetSceneData(SceneAsset sceneAsset, out SceneData data) public static int InvalidSceneIndex => -1; } -} +} \ No newline at end of file diff --git a/Assets/Editor Toolbox/Runtime/Serialization/SerializedScene.cs b/Assets/Editor Toolbox/Runtime/Serialization/SerializedScene.cs index 034078e5..d483bc7f 100644 --- a/Assets/Editor Toolbox/Runtime/Serialization/SerializedScene.cs +++ b/Assets/Editor Toolbox/Runtime/Serialization/SerializedScene.cs @@ -22,7 +22,7 @@ public class SerializedScene : ISerializationCallbackReceiver private string sceneName; [SerializeField, HideInInspector] private string scenePath; - [SerializeField, HideInInspector] + [SerializeField] private int buildIndex; @@ -37,7 +37,7 @@ void ISerializationCallbackReceiver.OnAfterDeserialize() private void UpdateProperties() { -#if UNITY_EDITOR +#if UNITY_EDITOR if (SceneSerializationUtility.TryGetSceneData(sceneReference, out var sceneData)) { SceneName = sceneData.SceneName; diff --git a/Assets/Editor Toolbox/package.json b/Assets/Editor Toolbox/package.json index 2e80a757..2d699f08 100644 --- a/Assets/Editor Toolbox/package.json +++ b/Assets/Editor Toolbox/package.json @@ -1,7 +1,7 @@ { "name": "com.browar.editor-toolbox", "displayName": "Editor Toolbox", - "version": "0.12.1", + "version": "0.12.3", "unity": "2018.1", "description": "Tools, custom attributes, drawers, hierarchy overlay, and other extensions for the Unity Editor.", "keywords": [ diff --git a/Assets/Examples/Editor/SampleScriptedImporter.cs b/Assets/Examples/Editor/SampleScriptedImporter.cs index 6d2b9b8f..8eb06e53 100644 --- a/Assets/Examples/Editor/SampleScriptedImporter.cs +++ b/Assets/Examples/Editor/SampleScriptedImporter.cs @@ -1,4 +1,5 @@ -using UnityEditor.AssetImporters; +#if UNITY_2020_2_OR_NEWER +using UnityEditor.AssetImporters; using UnityEngine; [ScriptedImporter(1, "sample")] @@ -11,4 +12,5 @@ public class SampleScriptedImporter : ScriptedImporter public override void OnImportAsset(AssetImportContext ctx) { } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/Assets/Examples/Editor/SampleScriptedImporterEditor.cs b/Assets/Examples/Editor/SampleScriptedImporterEditor.cs index 5d642270..481dba89 100644 --- a/Assets/Examples/Editor/SampleScriptedImporterEditor.cs +++ b/Assets/Examples/Editor/SampleScriptedImporterEditor.cs @@ -1,6 +1,8 @@ -using Toolbox.Editor.Editors; +#if UNITY_2020_2_OR_NEWER +using Toolbox.Editor.Editors; using UnityEditor; [CustomEditor(typeof(SampleScriptedImporter))] public class SampleScriptedImporterEditor : ToolboxScriptedImporterEditor -{ } \ No newline at end of file +{ } +#endif \ No newline at end of file diff --git a/Assets/Examples/Scenes/SampleScene.unity b/Assets/Examples/Scenes/SampleScene.unity index a220f5cc..67b4dcab 100644 --- a/Assets/Examples/Scenes/SampleScene.unity +++ b/Assets/Examples/Scenes/SampleScene.unity @@ -397,6 +397,101 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &580334316 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 580334320} + - component: {fileID: 580334319} + - component: {fileID: 580334318} + - component: {fileID: 580334317} + m_Layer: 0 + m_Name: SelectionCube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &580334317 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 580334316} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &580334318 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 580334316} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &580334319 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 580334316} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &580334320 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 580334316} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: -7.59, y: -2.12, z: 0.53} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 22 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &661896457 GameObject: m_ObjectHideFlags: 0 @@ -488,6 +583,81 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 7 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &663659267 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 663659268} + - component: {fileID: 663659270} + - component: {fileID: 663659269} + m_Layer: 5 + m_Name: Panel-B + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &663659268 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663659267} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 941031098} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 200, y: 200} + m_Pivot: {x: 0, y: 0} +--- !u!114 &663659269 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663659267} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 1, b: 0.15642643, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &663659270 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 663659267} + m_CullTransparentMesh: 1 --- !u!1 &666544666 GameObject: m_ObjectHideFlags: 0 @@ -548,6 +718,81 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 21 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &704298044 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 704298045} + - component: {fileID: 704298047} + - component: {fileID: 704298046} + m_Layer: 5 + m_Name: Panel-C + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &704298045 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704298044} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 941031098} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 300, y: 300} + m_Pivot: {x: 1, y: 1} +--- !u!114 &704298046 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704298044} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0.95602536, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &704298047 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 704298044} + m_CullTransparentMesh: 1 --- !u!1 &752799891 GameObject: m_ObjectHideFlags: 0 @@ -656,6 +901,83 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 19 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &941031097 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 941031098} + - component: {fileID: 941031100} + - component: {fileID: 941031099} + m_Layer: 5 + m_Name: Panel-A + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &941031098 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941031097} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 704298045} + - {fileID: 663659268} + m_Father: {fileID: 1245694416} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 100, y: 100} + m_SizeDelta: {x: 400, y: 400} + m_Pivot: {x: 0, y: 0} +--- !u!114 &941031099 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941031097} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &941031100 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 941031097} + m_CullTransparentMesh: 1 --- !u!1 &959025297 GameObject: m_ObjectHideFlags: 0 @@ -1016,6 +1338,106 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 17 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1245694412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1245694416} + - component: {fileID: 1245694415} + - component: {fileID: 1245694414} + - component: {fileID: 1245694413} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1245694413 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1245694412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1245694414 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1245694412} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1245694415 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1245694412} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 1 + m_Camera: {fileID: 534669904} + m_PlaneDistance: 10 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1245694416 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1245694412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 941031098} + m_Father: {fileID: 0} + m_RootOrder: 23 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} --- !u!1 &1414023086 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Examples/Scenes/StartupScene.unity b/Assets/Examples/Scenes/StartupScene.unity new file mode 100644 index 00000000..18fc0dbf --- /dev/null +++ b/Assets/Examples/Scenes/StartupScene.unity @@ -0,0 +1,173 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &284981408 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 284981410} + - component: {fileID: 284981409} + m_Layer: 0 + m_Name: SceneLoader + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &284981409 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 284981408} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3515fc2458d4146449db76ec05b91a23, type: 3} + m_Name: + m_EditorClassIdentifier: + scene: + sceneReference: {fileID: 102900000, guid: f11034f4657f51a47aac14f26410c500, type: 3} + sceneName: SampleScene + scenePath: Assets/Examples/Scenes/SampleScene.unity + buildIndex: 0 +--- !u!4 &284981410 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 284981408} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Examples/Scenes/StartupScene.unity.meta b/Assets/Examples/Scenes/StartupScene.unity.meta new file mode 100644 index 00000000..a843050b --- /dev/null +++ b/Assets/Examples/Scenes/StartupScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f78d57e2b3a7c4d41b107b859d04f165 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Examples/Scripts/SampleBehaviour1.cs b/Assets/Examples/Scripts/SampleBehaviour1.cs index f33fe623..16636ae9 100644 --- a/Assets/Examples/Scripts/SampleBehaviour1.cs +++ b/Assets/Examples/Scripts/SampleBehaviour1.cs @@ -109,4 +109,9 @@ public enum FlagExample public int bigNumber; [FormattedNumber("c")] public float currency; + + [Label("Label Width", skinStyle: SkinStyle.Box)] + + [LabelWidth(220.0f)] + public int veryVeryVeryVeryVeryLongName; } \ No newline at end of file diff --git a/Assets/Examples/Scripts/SceneLoader.cs b/Assets/Examples/Scripts/SceneLoader.cs new file mode 100644 index 00000000..9339337f --- /dev/null +++ b/Assets/Examples/Scripts/SceneLoader.cs @@ -0,0 +1,13 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +public class SceneLoader : MonoBehaviour +{ + [SerializeField, SceneDetails] + private SerializedScene scene; + + private void Start() + { + SceneManager.LoadScene(scene.BuildIndex); + } +} \ No newline at end of file diff --git a/Assets/Examples/Scripts/SceneLoader.cs.meta b/Assets/Examples/Scripts/SceneLoader.cs.meta new file mode 100644 index 00000000..6e615b43 --- /dev/null +++ b/Assets/Examples/Scripts/SceneLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3515fc2458d4146449db76ec05b91a23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Docs/labelwidth.png b/Docs/labelwidth.png new file mode 100644 index 00000000..f644e7e1 Binary files /dev/null and b/Docs/labelwidth.png differ diff --git a/Docs/sceneview.png b/Docs/sceneview.png new file mode 100644 index 00000000..a98398a1 Binary files /dev/null and b/Docs/sceneview.png differ diff --git a/README.md b/README.md index 69e04a50..7aa432cb 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,8 @@ Unity 2018.x or newer - Enable/disable Hierarchy overlay, choose allowed information - Enable/disable Project icons or/and assign own directories - Enable/disable Toolbox drawers or/and assign custom drawers - + - Enable/disable Toolbox Scene View and assign hotkeys + ## Table Of Contents - [Attributes & Drawers](#drawers) @@ -56,15 +57,17 @@ Unity 2018.x or newer - [Project](#project) - [Toolbar](#toolbar) - [Utilities](#utilities) + - [SceneView](#sceneview) ## Settings The most important file, allows the user to manage all available features. Can be accessed from the Project Settings window (Edit/Project Settings.../Editor Toolbox) or directly inside the Project window. Make sure to have one valid settings file per project. -Available features are divided into three groups: +Available features are divided into four groups: - Hierarchy - Project - Inspector +- SceneView Each module is described in its respective section. @@ -228,6 +231,15 @@ public int bigNumber; ![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/formattednumber.png) +#### LabelWidthAttribute + +```csharp +[LabelWidth(220.0f)] +public int veryVeryVeryVeryVeryLongName; +``` + +![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/labelwidth.png) + --- ### Toolbox Drawers @@ -844,3 +856,9 @@ Assets/Create/Editor Toolbox/ScriptableObject Creation Wizard ``` ![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/createso.png) + +### SceneView + +Select a specific object that is under the cursor (default key: left control). + +![inspector](https://github.com/arimger/Unity-Editor-Toolbox/blob/develop/Docs/sceneview.png) \ No newline at end of file