├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── Editor.meta ├── Editor ├── Editor Resources.meta ├── Editor Resources │ ├── Icons.meta │ └── Icons │ │ ├── icon_branch_I.png │ │ ├── icon_branch_I.png.meta │ │ ├── icon_branch_L.png │ │ ├── icon_branch_L.png.meta │ │ ├── icon_branch_T.png │ │ └── icon_branch_T.png.meta ├── Extensions.meta ├── Extensions │ ├── Texture2DExtensions.cs │ ├── Texture2DExtensions.cs.meta │ ├── VisualElementExstensions.cs │ └── VisualElementExstensions.cs.meta ├── Hierarchy.meta ├── Hierarchy │ ├── HierarchyEditor.cs │ ├── HierarchyEditor.cs.meta │ ├── HierarchyResources.cs │ ├── HierarchyResources.cs.meta │ ├── HierarchySettings.cs │ ├── HierarchySettings.cs.meta │ ├── HierarchySettingsProvider.cs │ ├── HierarchySettingsProvider.cs.meta │ ├── HierarchyWindow.cs │ ├── HierarchyWindow.cs.meta │ ├── Internal.meta │ ├── Internal │ │ ├── Resources.cs │ │ ├── Resources.cs.meta │ │ ├── RowItem.cs │ │ ├── RowItem.cs.meta │ │ ├── Styles.cs │ │ └── Styles.cs.meta │ ├── QuickInspect.meta │ ├── QuickInspect │ │ ├── QuickInspect.cs │ │ └── QuickInspect.cs.meta │ ├── QuickRename.meta │ └── QuickRename │ │ ├── SceneRenamePopup.cs │ │ ├── SceneRenamePopup.cs.meta │ │ ├── SelectionsRenamePopup.cs │ │ └── SelectionsRenamePopup.cs.meta ├── Resources.asset ├── Resources.asset.meta ├── Settings.asset ├── Settings.asset.meta ├── UI Elements.meta └── UI Elements │ ├── EditorHelpBox.cs │ ├── EditorHelpBox.cs.meta │ ├── Foldout.cs │ ├── Foldout.cs.meta │ ├── HorizontalLayout.cs │ ├── HorizontalLayout.cs.meta │ ├── VerticalLayout.cs │ └── VerticalLayout.cs.meta ├── Hierarchy.Editor.asmdef ├── Hierarchy.Editor.asmdef.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Third Party Notices.md ├── Third Party Notices.md.meta ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: quartzi 2 | custom: ["https://twitch.tv/quartzi"] 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # For Unity Tools Testing 14 | /[Ss]cenes/ 15 | /[Ss]cripts/ 16 | /[Tt]ests/ 17 | 18 | 19 | # MemoryCaptures can get excessive in size. 20 | # They also could contain extremely sensitive data 21 | /[Mm]emoryCaptures/ 22 | 23 | # Recordings can get excessive in size 24 | /[Rr]ecordings/ 25 | 26 | # Uncomment this line if you wish to ignore the asset store tools plugin 27 | # /[Aa]ssets/AssetStoreTools* 28 | 29 | # Autogenerated Jetbrains Rider plugin 30 | /[Aa]ssets/Plugins/Editor/JetBrains* 31 | 32 | # Visual Studio cache directory 33 | .vs/ 34 | 35 | # Gradle cache directory 36 | .gradle/ 37 | 38 | # Autogenerated VS/MD/Consulo solution and project files 39 | ExportedObj/ 40 | .consulo/ 41 | *.csproj 42 | *.unityproj 43 | *.sln 44 | *.suo 45 | *.tmp 46 | *.user 47 | *.userprefs 48 | *.pidb 49 | *.booproj 50 | *.svd 51 | *.pdb 52 | *.mdb 53 | *.opendb 54 | *.VC.db 55 | 56 | # Unity3D generated meta files 57 | *.pidb.meta 58 | *.pdb.meta 59 | *.mdb.meta 60 | 61 | # Unity3D generated file on crash reports 62 | sysinfo.txt 63 | 64 | # Builds 65 | *.apk 66 | *.aab 67 | *.unitypackage 68 | *.app 69 | 70 | # Crashlytics generated file 71 | crashlytics-build.properties 72 | 73 | # Packed Addressables 74 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 75 | 76 | # Temporary auto-generated Android Assets 77 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 78 | /[Aa]ssets/[Ss]treamingAssets/aa/* 79 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | artifacts/** 2 | build/** 3 | .DS_Store 4 | .npmrc 5 | .npmignore 6 | .gitignore 7 | .gitlab-ci.yml 8 | build.bat 9 | build.sh 10 | Scenes/** 11 | Scripts/** 12 | Tests/** -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 80f2fe0253dd6074b92caf21531ec482 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Editor Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f78a820ba5660b444a9148cd660761ae 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d7700bb5f0b97f44bbc416ac8056a0a3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_I.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quartzified-Tools/Quartzified-Hierarchy/7f3745d339835ee7587abfed05a63edb28544108/Editor/Editor Resources/Icons/icon_branch_I.png -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_I.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62535b6c7266bf440b9aa800596c7806 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: -1 36 | aniso: 1 37 | mipBias: -100 38 | wrapU: 1 39 | wrapV: 1 40 | wrapW: -1 41 | nPOTScale: 0 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 1 54 | spriteTessellationDetail: -1 55 | textureType: 2 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | - serializedVersion: 3 79 | buildTarget: Standalone 80 | maxTextureSize: 2048 81 | resizeAlgorithm: 0 82 | textureFormat: -1 83 | textureCompression: 1 84 | compressionQuality: 50 85 | crunchedCompression: 0 86 | allowsAlphaSplitting: 0 87 | overridden: 0 88 | androidETC2FallbackOverride: 0 89 | forceMaximumCompressionQuality_BC6H_BC7: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | bones: [] 96 | spriteID: 97 | internalID: 0 98 | vertices: [] 99 | indices: 100 | edges: [] 101 | weights: [] 102 | secondaryTextures: [] 103 | spritePackingTag: 104 | pSDRemoveMatte: 0 105 | pSDShowRemoveMatteOption: 0 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_L.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quartzified-Tools/Quartzified-Hierarchy/7f3745d339835ee7587abfed05a63edb28544108/Editor/Editor Resources/Icons/icon_branch_L.png -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_L.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bf7e68a3f72eea64f831f21ac8405a1c 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: -1 36 | aniso: 1 37 | mipBias: -100 38 | wrapU: 1 39 | wrapV: 1 40 | wrapW: -1 41 | nPOTScale: 0 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 1 54 | spriteTessellationDetail: -1 55 | textureType: 2 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | - serializedVersion: 3 79 | buildTarget: Standalone 80 | maxTextureSize: 2048 81 | resizeAlgorithm: 0 82 | textureFormat: -1 83 | textureCompression: 1 84 | compressionQuality: 50 85 | crunchedCompression: 0 86 | allowsAlphaSplitting: 0 87 | overridden: 0 88 | androidETC2FallbackOverride: 0 89 | forceMaximumCompressionQuality_BC6H_BC7: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | bones: [] 96 | spriteID: 97 | internalID: 0 98 | vertices: [] 99 | indices: 100 | edges: [] 101 | weights: [] 102 | secondaryTextures: [] 103 | spritePackingTag: 104 | pSDRemoveMatte: 0 105 | pSDShowRemoveMatteOption: 0 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_T.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Quartzified-Tools/Quartzified-Hierarchy/7f3745d339835ee7587abfed05a63edb28544108/Editor/Editor Resources/Icons/icon_branch_T.png -------------------------------------------------------------------------------- /Editor/Editor Resources/Icons/icon_branch_T.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 133b094552954f64aa4f77e744113d9a 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: -1 36 | aniso: 1 37 | mipBias: -100 38 | wrapU: 1 39 | wrapV: 1 40 | wrapW: -1 41 | nPOTScale: 0 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 1 54 | spriteTessellationDetail: -1 55 | textureType: 2 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | - serializedVersion: 3 79 | buildTarget: Standalone 80 | maxTextureSize: 2048 81 | resizeAlgorithm: 0 82 | textureFormat: -1 83 | textureCompression: 1 84 | compressionQuality: 50 85 | crunchedCompression: 0 86 | allowsAlphaSplitting: 0 87 | overridden: 0 88 | androidETC2FallbackOverride: 0 89 | forceMaximumCompressionQuality_BC6H_BC7: 0 90 | spriteSheet: 91 | serializedVersion: 2 92 | sprites: [] 93 | outline: [] 94 | physicsShape: [] 95 | bones: [] 96 | spriteID: 97 | internalID: 0 98 | vertices: [] 99 | indices: 100 | edges: [] 101 | weights: [] 102 | secondaryTextures: [] 103 | spritePackingTag: 104 | pSDRemoveMatte: 0 105 | pSDShowRemoveMatteOption: 0 106 | userData: 107 | assetBundleName: 108 | assetBundleVariant: 109 | -------------------------------------------------------------------------------- /Editor/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: efb7741c600c7884393b5a3fdb79b815 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Extensions/Texture2DExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Quartzified.Tools.Hierarchy 5 | { 6 | public static class Texture2DExtensions 7 | { 8 | public static string PNGImageEncodeBase64(this Texture2D texture2D) 9 | { 10 | var bytes = texture2D.EncodeToPNG(); 11 | var base64 = Convert.ToBase64String(bytes); 12 | return base64; 13 | } 14 | 15 | public static Texture2D PNGImageDecodeBase64(this string base64) 16 | { 17 | return Convert.FromBase64String(base64).PNGImageDecode(); 18 | } 19 | 20 | public static Texture2D PNGImageDecode(this byte[] bytes) 21 | { 22 | Texture2D texture2D = new Texture2D(0, 0, TextureFormat.RGBA32, false); 23 | texture2D.hideFlags = HideFlags.HideAndDontSave; 24 | #if UNITY_EDITOR 25 | texture2D.alphaIsTransparency = true; 26 | #endif 27 | texture2D.LoadImage(bytes); 28 | texture2D.Apply(); 29 | return texture2D; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Editor/Extensions/Texture2DExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d494eb5399fa0ab48a22baaf16f73661 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Extensions/VisualElementExstensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using UnityEngine; 3 | using UnityEngine.UIElements; 4 | 5 | namespace Quartzified.Tools.Hierarchy 6 | { 7 | public static class UIElementsExstensions 8 | { 9 | public static void StyleDisplay(this VisualElement ui, DisplayStyle displayStyle) => 10 | ui.style.display = displayStyle; 11 | 12 | public static void StyleDisplay(this VisualElement ui, bool value) => 13 | ui.StyleDisplay(value ? DisplayStyle.Flex : DisplayStyle.None); 14 | 15 | public static bool IsDisplaying(this VisualElement ui) => ui.style.display == DisplayStyle.Flex; 16 | 17 | public static void StyleVisibility(this VisualElement ui, Visibility visibility) => 18 | ui.style.visibility = visibility; 19 | 20 | public static void StyleVisibility(this VisualElement ui, bool value) => 21 | ui.StyleVisibility(value ? Visibility.Visible : Visibility.Hidden); 22 | 23 | public static Vector2 StylePosition(this VisualElement ui) 24 | { 25 | return new Vector2(ui.style.left.value.value, ui.style.top.value.value); 26 | } 27 | 28 | public static Vector2 StyleSize(this VisualElement ui) 29 | { 30 | return new Vector2(ui.style.width.value.value, ui.style.height.value.value); 31 | } 32 | 33 | public static Vector2 StyleMinSize(this VisualElement ui) 34 | { 35 | return new Vector2(ui.style.minWidth.value.value, ui.style.minHeight.value.value); 36 | } 37 | 38 | public static Vector2 StyleMaxSize(this VisualElement ui) 39 | { 40 | return new Vector2(ui.style.maxWidth.value.value, ui.style.maxHeight.value.value); 41 | } 42 | 43 | public static void StylePosition(this VisualElement ui, Vector2 position) 44 | { 45 | ui.StyleLeft(position.x); 46 | ui.StyleTop(position.y); 47 | } 48 | 49 | public static void StylePosition(this VisualElement ui, StyleLength x, StyleLength y) 50 | { 51 | ui.StyleLeft(x); 52 | ui.StyleTop(y); 53 | } 54 | 55 | public static void StyleTop(this VisualElement ui, StyleLength value) => ui.style.top = value; 56 | 57 | public static void StyleBottom(this VisualElement ui, StyleLength value) => ui.style.bottom = value; 58 | 59 | public static void StyleLeft(this VisualElement ui, StyleLength value) => ui.style.left = value; 60 | 61 | public static void StyleRight(this VisualElement ui, StyleLength value) => ui.style.right = value; 62 | 63 | public static float StyleTop(this VisualElement ui) => ui.style.top.value.value; 64 | 65 | public static float StyleBottom(this VisualElement ui) => ui.style.bottom.value.value; 66 | 67 | public static float StyleLeft(this VisualElement ui) => ui.style.left.value.value; 68 | 69 | public static float StyleRight(this VisualElement ui) => ui.style.right.value.value; 70 | 71 | public static void StylePosition(this VisualElement ui, Position type) => ui.style.position = type; 72 | 73 | public static void StyleSize(this VisualElement ui, StyleLength width, StyleLength height) 74 | { 75 | ui.StyleWidth(width); 76 | ui.StyleHeight(height); 77 | } 78 | 79 | public static void StyleSize(this VisualElement ui, Vector2 size) => StyleSize(ui, size.x, size.y); 80 | 81 | public static void StyleMinSize(this VisualElement ui, StyleLength width, StyleLength height) 82 | { 83 | ui.StyleMinWidth(width); 84 | ui.StyleMinHeight(height); 85 | } 86 | 87 | public static void StyleMaxSize(this VisualElement ui, StyleLength width, StyleLength height) 88 | { 89 | ui.StyleMaxWidth(width); 90 | ui.StyleMaxHeight(height); 91 | } 92 | 93 | 94 | public static void StyleWidth(this VisualElement ui, StyleLength width) => ui.style.width = width; 95 | 96 | public static void StyleMinWidth(this VisualElement ui, StyleLength width) => ui.style.minWidth = width; 97 | 98 | public static void StyleMaxWidth(this VisualElement ui, StyleLength width) => ui.style.maxWidth = width; 99 | 100 | public static void StyleHeight(this VisualElement ui, StyleLength height) => ui.style.height = height; 101 | 102 | public static void StyleMinHeight(this VisualElement ui, StyleLength height) => ui.style.minHeight = height; 103 | 104 | public static void StyleMaxHeight(this VisualElement ui, StyleLength height) => ui.style.maxHeight = height; 105 | 106 | public static void StyleFont(this VisualElement ui, FontStyle fontStyle) => 107 | ui.style.unityFontStyleAndWeight = fontStyle; 108 | 109 | public static void StyleFontSize(this VisualElement ui, StyleLength size) => ui.style.fontSize = size; 110 | 111 | public static void StyleTextAlign(this VisualElement ui, TextAnchor textAnchor) => 112 | ui.style.unityTextAlign = textAnchor; 113 | 114 | public static void StyleAlignSelf(this VisualElement ui, Align align) => ui.style.alignSelf = align; 115 | 116 | public static void StyleAlignItem(this VisualElement ui, Align align) => ui.style.alignItems = align; 117 | 118 | public static void StyleJustifyContent(this VisualElement ui, Justify justify) => 119 | ui.style.justifyContent = justify; 120 | 121 | public static void StyleFlexDirection(this VisualElement ui, FlexDirection flexDirection) => 122 | ui.style.flexDirection = flexDirection; 123 | 124 | public static void StyleMargin(this VisualElement ui, StyleLength value) => 125 | ui.StyleMargin(value, value, value, value); 126 | 127 | public static void StyleMargin(this VisualElement ui, StyleLength left, StyleLength right, StyleLength top, 128 | StyleLength bottom) 129 | { 130 | ui.style.marginLeft = left; 131 | ui.style.marginRight = right; 132 | ui.style.marginTop = top; 133 | ui.style.marginBottom = bottom; 134 | } 135 | 136 | public static void StyleMarginLeft(this VisualElement ui, StyleLength value) => ui.style.marginLeft = value; 137 | 138 | public static void StyleMarginRight(this VisualElement ui, StyleLength value) => ui.style.marginRight = value; 139 | 140 | public static void StyleMarginTop(this VisualElement ui, StyleLength value) => ui.style.marginTop = value; 141 | 142 | public static void StyleMarginBottom(this VisualElement ui, StyleLength value) => ui.style.marginBottom = value; 143 | 144 | public static void StylePadding(this VisualElement ui, StyleLength value) => 145 | ui.StylePadding(value, value, value, value); 146 | 147 | public static void StylePadding(this VisualElement ui, StyleLength left, StyleLength right, StyleLength top, 148 | StyleLength bottom) 149 | { 150 | ui.style.paddingLeft = left; 151 | ui.style.paddingRight = right; 152 | ui.style.paddingTop = top; 153 | ui.style.paddingBottom = bottom; 154 | } 155 | 156 | public static void StylePaddingLeft(this VisualElement ui, StyleLength value) => ui.style.paddingLeft = value; 157 | 158 | public static void StylePaddingRight(this VisualElement ui, StyleLength value) => ui.style.paddingRight = value; 159 | 160 | public static void StylePaddingTop(this VisualElement ui, StyleLength value) => ui.style.paddingTop = value; 161 | 162 | public static void StylePaddingBottom(this VisualElement ui, StyleLength value) => 163 | ui.style.paddingBottom = value; 164 | 165 | public static void StyleBorderRadius(this VisualElement ui, StyleLength radius) => 166 | ui.StyleBorderRadius(radius, radius, radius, radius); 167 | 168 | public static void StyleBorderRadius(this VisualElement ui, StyleLength topLeft, StyleLength topRight, 169 | StyleLength bottomLeft, StyleLength bottomRight) 170 | { 171 | ui.style.borderTopLeftRadius = topLeft; 172 | ui.style.borderTopRightRadius = topRight; 173 | ui.style.borderBottomLeftRadius = bottomLeft; 174 | ui.style.borderBottomRightRadius = bottomRight; 175 | } 176 | 177 | public static void StyleBorderWidth(this VisualElement ui, StyleFloat width) => 178 | ui.StyleBorderWidth(width, width, width, width); 179 | 180 | public static void StyleBorderWidth(this VisualElement ui, StyleFloat left, StyleFloat right, StyleFloat top, 181 | StyleFloat bottom) 182 | { 183 | ui.style.borderLeftWidth = left; 184 | ui.style.borderRightWidth = right; 185 | ui.style.borderTopWidth = top; 186 | ui.style.borderBottomWidth = bottom; 187 | } 188 | 189 | public static void StyleBorderColor(this VisualElement ui, StyleColor color) => 190 | ui.StyleBorderColor(color, color, color, color); 191 | 192 | public static void StyleBorderColor(this VisualElement ui, StyleColor left, StyleColor right, StyleColor top, 193 | StyleColor bottom) 194 | { 195 | ui.style.borderLeftColor = left; 196 | ui.style.borderRightColor = right; 197 | ui.style.borderTopColor = top; 198 | ui.style.borderBottomColor = bottom; 199 | } 200 | 201 | public static void StyleFlexBasisAsPercent(this VisualElement ui, StyleLength basis) => 202 | ui.style.flexBasis = basis; 203 | 204 | public static void StyleFlexGrow(this VisualElement ui, StyleFloat grow) => ui.style.flexGrow = grow; 205 | 206 | public static void StyleBackgroundColor(this VisualElement ui, StyleColor color) => 207 | ui.style.backgroundColor = color; 208 | 209 | public static void StyleTextColor(this VisualElement ui, StyleColor color) => ui.style.color = color; 210 | 211 | public static VisualElement FindChildren(this VisualElement ui, string name) 212 | { 213 | return ui.Children().ToList().Find(childElement => childElement.name == name); 214 | } 215 | 216 | public static T FindChildren(this VisualElement ui, string name) where T : VisualElement 217 | { 218 | return ui.FindChildren(name) as T; 219 | } 220 | 221 | public static VisualElement FindChildrenPhysicalHierarchy(this VisualElement ui, string name) 222 | { 223 | return ui.hierarchy.Children().ToList().Find(childElement => childElement.name == name); 224 | } 225 | 226 | public static VisualElement FindChildrenPhysicalHierarchy(this VisualElement ui, string name) 227 | where T : VisualElement 228 | { 229 | return ui.FindChildrenPhysicalHierarchy(name) as T; 230 | } 231 | } 232 | } -------------------------------------------------------------------------------- /Editor/Extensions/VisualElementExstensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4507fa051b982c14fbad087a44b2da52 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57c6a614a34497d4a97c4a436fded39c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using UnityEditor; 7 | using UnityEditor.SceneManagement; 8 | using UnityEditorInternal; 9 | using UnityEditor.Callbacks; 10 | using UnityEngine; 11 | using UnityEngine.SceneManagement; 12 | using System.Text.RegularExpressions; 13 | 14 | namespace Quartzified.Tools.Hierarchy 15 | { 16 | [InitializeOnLoad] 17 | public sealed class HierarchyEditor 18 | { 19 | internal const int GLOBAL_SPACE_OFFSET_LEFT = 16 * 2; 20 | 21 | static HierarchyEditor instance; 22 | 23 | public static HierarchyEditor Instance 24 | { 25 | get 26 | { 27 | if (instance == null) 28 | instance = new HierarchyEditor(); 29 | 30 | return instance; 31 | } 32 | private set { instance = value; } 33 | } 34 | 35 | Dictionary selectedComponents = new Dictionary(); 36 | Dictionary dicComponents = new Dictionary(StringComparer.Ordinal); 37 | UnityEngine.Object activeComponent; 38 | 39 | GUIContent tooltipContent = new GUIContent(); 40 | 41 | HierarchySettings settings; 42 | HierarchyResources resources; 43 | 44 | HierarchySettings.ThemeData ThemeData 45 | { 46 | get { return settings.usedThemeData; } 47 | } 48 | 49 | int deepestRow = int.MinValue; 50 | int previousRowIndex = int.MinValue; 51 | 52 | int sceneIndex = 0; 53 | Scene currentScene; 54 | Scene previousScene; 55 | 56 | public static bool IsMultiScene 57 | { 58 | get { return SceneManager.sceneCount > 1; } 59 | } 60 | 61 | bool selectionStyleAfterInvoke = false; 62 | bool checkingAllHierarchy = false; 63 | 64 | Event currentEvent; 65 | 66 | RowItem rowItem = new RowItem(); 67 | RowItem previousElement = null; 68 | WidthUse widthUse = WidthUse.zero; 69 | 70 | static HierarchyEditor() 71 | { 72 | if (instance == null) 73 | instance = new HierarchyEditor(); 74 | } 75 | 76 | public HierarchyEditor() 77 | { 78 | InternalReflection(); 79 | EditorApplication.update += EditorAwake; 80 | EditorApplication.hierarchyWindowItemOnGUI += UpdateHierarchyItem; 81 | AssetDatabase.importPackageCompleted += ImportPackageCompleted; 82 | } 83 | 84 | void UpdateHierarchyItem(int instanceID, Rect selectionRect) 85 | { 86 | GameObject hierarchyObject = EditorUtility.InstanceIDToObject(instanceID) as GameObject; 87 | 88 | if(hierarchyObject != null) 89 | { 90 | HierarchySettings settings = HierarchySettings.instance; 91 | HierarchySettings.HeaderTagData data = settings?.tagData; 92 | selectionRect.width = selectionRect.width - 8; 93 | 94 | if (data == null) 95 | return; 96 | 97 | for (int i = 0; i < data.headerCount; i++) 98 | { 99 | if (string.IsNullOrEmpty(data.headerTag[i])) 100 | continue; 101 | 102 | string newName = hierarchyObject.name; 103 | int charCount = data.headerTag[i].Length + 1; 104 | 105 | string[] objectWords = hierarchyObject.name.Split(' '); 106 | 107 | if (objectWords.Length <= 1) 108 | return; 109 | 110 | if (objectWords[0].ToLower().Equals(data.headerTag[i].ToLower(), StringComparison.Ordinal)) 111 | { 112 | newName = newName.Substring(charCount, newName.Length - charCount); 113 | ChangeHierarchyItem(selectionRect, newName, data.headerColor[i]); 114 | } 115 | } 116 | } 117 | 118 | } 119 | 120 | static void ChangeHierarchyItem(Rect selectionRect, string name, Color color) 121 | { 122 | color.a = 1; 123 | EditorGUI.DrawRect(selectionRect, color); 124 | 125 | Rect nameRect = selectionRect; 126 | nameRect.center = new Vector2(nameRect.center.x + (nameRect.width / 2) - name.Length * 4, nameRect.center.y); 127 | 128 | GUIStyle style = new GUIStyle(); 129 | style.fontStyle = FontStyle.Bold; 130 | style.fontSize = 14; 131 | style.richText = true; 132 | style.normal.textColor = Color.white; 133 | 134 | EditorGUI.LabelField(nameRect, name, style); 135 | } 136 | 137 | static string[] GetSurroundedString(string value) 138 | { 139 | string[] results = Regex.Matches(value, @"%(.+?)%") 140 | .Cast() 141 | .Select(m => m.Groups[1].Value) 142 | .ToArray(); 143 | 144 | return results; 145 | } 146 | 147 | static string GetFirstSurroundedString(string value) 148 | { 149 | string[] results = Regex.Matches(value, @"%(.+?)%") 150 | .Cast() 151 | .Select(m => m.Groups[1].Value) 152 | .ToArray(); 153 | 154 | return results[0]; 155 | } 156 | 157 | static List InternalEditorType = new List(); 158 | static Dictionary dicInternalEditorType = new Dictionary(); 159 | static List DisplayOnHierarchyScriptType = new List(); 160 | static Dictionary dicDisplayOnHierarchyScriptType = new Dictionary(); 161 | 162 | static Type SceneHierarchyWindow; 163 | static Type SceneHierarchy; 164 | static Type GameObjectTreeViewGUI; 165 | 166 | static FieldInfo m_SceneHierarchy; 167 | static FieldInfo m_TreeView; 168 | static PropertyInfo gui; 169 | static FieldInfo k_IconWidth; 170 | 171 | static Func lastInteractedHierarchyWindowDelegate; 172 | static Func GetAllSceneHierarchyWindowsDelegate; 173 | static Func IconSelectorShowAtPositionDelegate; 174 | static Action DisplayObjectContextMenuDelegate; 175 | 176 | public static Action OnRepaintHierarchyWindowCallback; 177 | public static Action OnWindowsReorderedCallback; 178 | 179 | static void InternalReflection() 180 | { 181 | var arrayInteralEditorType = typeof(Editor).Assembly.GetTypes(); 182 | InternalEditorType = arrayInteralEditorType.ToList(); 183 | dicInternalEditorType = arrayInteralEditorType.ToDictionary(type => type.FullName); 184 | 185 | FieldInfo refreshHierarchy = typeof(EditorApplication).GetField(nameof(refreshHierarchy), BindingFlags.Static | BindingFlags.NonPublic); 186 | MethodInfo OnRepaintHierarchyWindow = typeof(HierarchyEditor).GetMethod(nameof(OnRepaintHierarchyWindow), BindingFlags.NonPublic | BindingFlags.Static); 187 | Delegate refreshHierarchyDelegate = Delegate.CreateDelegate(typeof(EditorApplication.CallbackFunction), OnRepaintHierarchyWindow); 188 | refreshHierarchy.SetValue(null, refreshHierarchyDelegate); 189 | 190 | 191 | FieldInfo windowsReordered = typeof(EditorApplication).GetField(nameof(windowsReordered), BindingFlags.Static | BindingFlags.NonPublic); 192 | MethodInfo OnWindowsReordered = typeof(HierarchyEditor).GetMethod(nameof(OnWindowsReordered), BindingFlags.NonPublic | BindingFlags.Static); 193 | Delegate windowsReorderedDelegate = Delegate.CreateDelegate(typeof(EditorApplication.CallbackFunction), OnWindowsReordered); 194 | windowsReordered.SetValue(null, windowsReorderedDelegate); 195 | 196 | { 197 | dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(SceneHierarchyWindow), out SceneHierarchyWindow); 198 | dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(GameObjectTreeViewGUI), out GameObjectTreeViewGUI); //GameObjectTreeViewGUI : TreeViewGUI 199 | dicInternalEditorType.TryGetValue(nameof(UnityEditor) + "." + nameof(SceneHierarchy), out SceneHierarchy); 200 | } 201 | 202 | FieldInfo s_LastInteractedHierarchy = SceneHierarchyWindow.GetField(nameof(s_LastInteractedHierarchy), BindingFlags.NonPublic | BindingFlags.Static); 203 | 204 | MethodInfo lastInteractedHierarchyWindow = SceneHierarchyWindow.GetProperty(nameof(lastInteractedHierarchyWindow), BindingFlags.Static | BindingFlags.Public).GetGetMethod(); 205 | lastInteractedHierarchyWindowDelegate = Delegate.CreateDelegate(typeof(Func), lastInteractedHierarchyWindow) as Func; 206 | 207 | MethodInfo GetAllSceneHierarchyWindows = SceneHierarchyWindow.GetMethod(nameof(GetAllSceneHierarchyWindows), BindingFlags.Static | BindingFlags.Public); 208 | GetAllSceneHierarchyWindowsDelegate = Delegate.CreateDelegate(typeof(Func), GetAllSceneHierarchyWindows) as Func; 209 | 210 | { 211 | m_SceneHierarchy = SceneHierarchyWindow.GetField(nameof(m_SceneHierarchy), BindingFlags.NonPublic | BindingFlags.Instance); 212 | m_TreeView = SceneHierarchy.GetField(nameof(m_TreeView), BindingFlags.NonPublic | BindingFlags.Instance); 213 | gui = m_TreeView.FieldType.GetProperty(nameof(gui).ToLower(), BindingFlags.Public | BindingFlags.Instance); 214 | k_IconWidth = GameObjectTreeViewGUI.GetField(nameof(k_IconWidth), BindingFlags.Public | BindingFlags.Instance); 215 | } 216 | 217 | MethodInfo DisplayObjectContextMenu = typeof(EditorUtility).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single 218 | ( 219 | method => method.Name == nameof(DisplayObjectContextMenu) && method.GetParameters()[1].ParameterType == typeof(UnityEngine.Object) 220 | ); 221 | DisplayObjectContextMenuDelegate = Delegate.CreateDelegate(typeof(Action), DisplayObjectContextMenu) as Action; 222 | 223 | 224 | Type IconSelector = typeof(EditorWindow).Assembly.GetTypes().Single(type => 225 | type.BaseType == typeof(EditorWindow) && type.Name == nameof(IconSelector)) as Type; 226 | MethodInfo ShowAtPosition = IconSelector.GetMethods(BindingFlags.Static | BindingFlags.NonPublic).Single 227 | ( 228 | method => method.Name == nameof(ShowAtPosition) && 229 | method.GetParameters()[0].ParameterType == typeof(UnityEngine.Object) 230 | ); 231 | IconSelectorShowAtPositionDelegate = Delegate.CreateDelegate(typeof(Func), ShowAtPosition) as Func; 232 | 233 | GetItemAndRowIndexMethod = m_TreeView.FieldType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Single(method => method.Name == "GetItemAndRowIndex"); 234 | 235 | m_TreeView_IData = m_TreeView.FieldType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Single(property => property.Name == "data"); 236 | 237 | m_Rows = InternalEditorType.Find(type => type.Name == "TreeViewDataSource").GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Single(field => field.Name.Contains(nameof(m_Rows))); 238 | } 239 | 240 | public static IEnumerable GetAllSceneHierarchyWindows() => GetAllSceneHierarchyWindowsDelegate(); 241 | 242 | public static void DisplayObjectContextMenu(Rect rect, UnityEngine.Object unityObject, int value) => DisplayObjectContextMenuDelegate(rect, unityObject, value); 243 | 244 | public static bool IconSelectorShowAtPosition(GameObject gameObject, Rect rect, bool value) => IconSelectorShowAtPositionDelegate(gameObject, rect, value); 245 | 246 | private static MethodInfo GetItemAndRowIndexMethod; 247 | private static PropertyInfo m_TreeView_IData; 248 | private static FieldInfo m_Rows; 249 | 250 | static void OnRepaintHierarchyWindow() 251 | { 252 | OnRepaintHierarchyWindowCallback?.Invoke(); 253 | } 254 | 255 | static void OnWindowsReordered() 256 | { 257 | OnWindowsReorderedCallback?.Invoke(); 258 | } 259 | 260 | void EditorAwake() 261 | { 262 | settings = HierarchySettings.GetAssets(); 263 | if (settings is null) return; 264 | OnSettingsChanged(nameof(settings.components)); 265 | settings.onSettingsChanged += OnSettingsChanged; 266 | 267 | resources = HierarchyResources.GetAssets(); 268 | if (resources is null) return; 269 | resources.GenerateKeyForAssets(); 270 | 271 | EditorApplication.hierarchyWindowItemOnGUI += HierarchyOnGUI; 272 | 273 | if (settings.activeHierarchy) 274 | Invoke(); 275 | else 276 | Dispose(); 277 | 278 | EditorApplication.update -= EditorAwake; 279 | } 280 | 281 | void ImportPackageCompleted(string packageName) 282 | { 283 | } 284 | 285 | void OnSettingsChanged(string param) 286 | { 287 | switch (param) 288 | { 289 | case nameof(settings.components): 290 | dicComponents.Clear(); 291 | foreach (string componentType in settings.components) 292 | { 293 | if (!dicComponents.ContainsKey(componentType)) 294 | dicComponents.Add(componentType, componentType); 295 | } 296 | 297 | break; 298 | } 299 | 300 | EditorApplication.RepaintHierarchyWindow(); 301 | } 302 | 303 | public void Invoke() 304 | { 305 | EditorSceneManager.newSceneCreated += OnNewSceneCreated; 306 | EditorSceneManager.sceneOpened += OnSceneOpened; 307 | EditorSceneManager.sceneClosed += OnSceneClosed; 308 | EditorSceneManager.sceneLoaded += OnSceneLoaded; 309 | EditorSceneManager.sceneUnloaded += OnSceneUnloaded; 310 | EditorSceneManager.sceneSaved += OnSceneSaved; 311 | EditorSceneManager.sceneDirtied += OnSceneDirtied; 312 | 313 | EditorApplication.hierarchyChanged += OnHierarchyChanged; 314 | EditorApplication.modifierKeysChanged += OnModifierKeysChanged; 315 | 316 | PrefabUtility.prefabInstanceUpdated += OnPrefabUpdated; 317 | PrefabStage.prefabStageOpened += OnPrefabStageOpened; 318 | PrefabStage.prefabStageClosing += OnPrefabStageClosing; 319 | 320 | EditorApplication.update += OnEditorUpdate; 321 | 322 | selectionStyleAfterInvoke = false; 323 | EditorApplication.RepaintHierarchyWindow(); 324 | EditorApplication.RepaintProjectWindow(); 325 | } 326 | 327 | public void Dispose() 328 | { 329 | EditorSceneManager.newSceneCreated -= OnNewSceneCreated; 330 | EditorSceneManager.sceneOpened -= OnSceneOpened; 331 | EditorSceneManager.sceneClosed -= OnSceneClosed; 332 | EditorSceneManager.sceneLoaded -= OnSceneLoaded; 333 | EditorSceneManager.sceneUnloaded -= OnSceneUnloaded; 334 | EditorSceneManager.sceneSaved -= OnSceneSaved; 335 | EditorSceneManager.sceneDirtied -= OnSceneDirtied; 336 | 337 | EditorApplication.hierarchyChanged -= OnHierarchyChanged; 338 | EditorApplication.modifierKeysChanged -= OnModifierKeysChanged; 339 | 340 | PrefabUtility.prefabInstanceUpdated -= OnPrefabUpdated; 341 | PrefabStage.prefabStageOpened -= OnPrefabStageOpened; 342 | PrefabStage.prefabStageClosing -= OnPrefabStageClosing; 343 | 344 | EditorApplication.update -= OnEditorUpdate; 345 | 346 | 347 | foreach (EditorWindow window in GetAllSceneHierarchyWindowsDelegate()) 348 | { 349 | window.titleContent.text = "Hierarchy"; 350 | } 351 | 352 | EditorApplication.RepaintHierarchyWindow(); 353 | EditorApplication.RepaintProjectWindow(); 354 | } 355 | 356 | double lastTimeSinceStartup = EditorApplication.timeSinceStartup; 357 | 358 | void OnEditorUpdate() 359 | { 360 | if (EditorApplication.timeSinceStartup - lastTimeSinceStartup >= 1) 361 | { 362 | DelayCall(); 363 | lastTimeSinceStartup = EditorApplication.timeSinceStartup; 364 | } 365 | } 366 | 367 | void DelayCall() 368 | { 369 | if (checkingAllHierarchy == true) 370 | { 371 | for (int i = 0; i < HierarchyWindow.windows.Count; ++i) 372 | { 373 | if (HierarchyWindow.windows[i].editorWindow == null) 374 | { 375 | HierarchyWindow.windows[i].Dispose(); 376 | --i; 377 | } 378 | } 379 | 380 | foreach (EditorWindow window in GetAllSceneHierarchyWindowsDelegate()) 381 | { 382 | if (!HierarchyWindow.instances.ContainsKey(window.GetInstanceID())) 383 | { 384 | var hierarchyWindow = new HierarchyWindow(window); 385 | hierarchyWindow.SetWindowTitle("Quartzified Hierarchy"); 386 | } 387 | } 388 | 389 | checkingAllHierarchy = false; 390 | } 391 | 392 | if (hierarchyChangedRequireUpdating == true) 393 | { 394 | hierarchyChangedRequireUpdating = false; 395 | } 396 | } 397 | 398 | void OnModifierKeysChanged() 399 | { 400 | } 401 | 402 | [DidReloadScripts] 403 | static void OnEditorCompiled() 404 | { 405 | } 406 | 407 | void OnNewSceneCreated(Scene scene, NewSceneSetup setup, NewSceneMode mode) 408 | { 409 | } 410 | 411 | void OnSceneOpened(Scene scene, OpenSceneMode mode) 412 | { 413 | if (settings is null) return; 414 | } 415 | 416 | void OnSceneClosed(Scene scene) 417 | { 418 | } 419 | 420 | void OnSceneLoaded(Scene scene, LoadSceneMode mode) 421 | { 422 | } 423 | 424 | void OnSceneUnloaded(Scene scene) 425 | { 426 | } 427 | 428 | void OnSceneSaved(Scene scene) 429 | { 430 | } 431 | 432 | void OnSceneDirtied(Scene scene) 433 | { 434 | } 435 | 436 | bool hierarchyChangedRequireUpdating = false; 437 | 438 | void OnHierarchyChanged() 439 | { 440 | hierarchyChangedRequireUpdating = true; 441 | } 442 | 443 | void OnPrefabUpdated(GameObject prefab) 444 | { 445 | } 446 | 447 | bool prefabStageChanged = false; 448 | 449 | void OnPrefabStageOpened(PrefabStage stage) 450 | { 451 | prefabStageChanged = true; 452 | } 453 | 454 | void OnPrefabStageClosing(PrefabStage stage) 455 | { 456 | prefabStageChanged = true; 457 | } 458 | 459 | void HierarchyOnGUI(int selectionID, Rect selectionRect) 460 | { 461 | currentEvent = Event.current; 462 | 463 | if (currentEvent.type == EventType.KeyDown && currentEvent.keyCode == KeyCode.H && currentEvent.control) 464 | { 465 | if (!settings.activeHierarchy) 466 | Invoke(); 467 | else 468 | Dispose(); 469 | 470 | settings.activeHierarchy = !settings.activeHierarchy; 471 | currentEvent.Use(); 472 | } 473 | 474 | if (!settings.activeHierarchy) 475 | return; 476 | 477 | if (currentEvent.control && currentEvent.keyCode == KeyCode.D) 478 | return; 479 | 480 | if (currentEvent.type == EventType.Layout) 481 | { 482 | if (prefabStageChanged) 483 | { 484 | prefabStageChanged = false; 485 | } 486 | 487 | return; 488 | } 489 | 490 | checkingAllHierarchy = true; 491 | 492 | if (selectionStyleAfterInvoke == false && currentEvent.type == EventType.MouseDown) 493 | { 494 | selectionStyleAfterInvoke = true; 495 | } 496 | 497 | rowItem.Dispose(); 498 | rowItem.ID = selectionID; 499 | rowItem.gameObject = EditorUtility.InstanceIDToObject(rowItem.ID) as GameObject; 500 | rowItem.rect = selectionRect; 501 | rowItem.rowIndex = GetRowIndex(selectionRect); 502 | rowItem.isSelected = InSelection(selectionID); 503 | rowItem.isFirstRow = IsFirstRow(selectionRect); 504 | rowItem.isFirstElement = IsFirstElement(selectionRect); 505 | 506 | rowItem.isNull = rowItem.gameObject == null ? true : false; 507 | 508 | if (!rowItem.isNull) 509 | { 510 | 511 | rowItem.isDirty = EditorUtility.IsDirty(selectionID); 512 | 513 | if (true && rowItem.isDirty) 514 | { 515 | rowItem.isPrefab = PrefabUtility.IsPartOfAnyPrefab(rowItem.gameObject); 516 | 517 | if (rowItem.isPrefab) 518 | rowItem.isPrefabMissing = PrefabUtility.IsPrefabAssetMissing(rowItem.gameObject); 519 | } 520 | } 521 | 522 | rowItem.isRootObject = rowItem.isNull || rowItem.gameObject.transform.parent == null ? true : false; 523 | rowItem.isMouseHovering = selectionRect.Contains(currentEvent.mousePosition); 524 | 525 | if (rowItem.isFirstRow) //Instance always null 526 | { 527 | sceneIndex = 0; 528 | 529 | if (deepestRow > previousRowIndex) 530 | deepestRow = previousRowIndex; 531 | } 532 | 533 | if (rowItem.isNull) 534 | { 535 | if (!IsMultiScene) 536 | currentScene = SceneManager.GetActiveScene(); 537 | else 538 | { 539 | if (!rowItem.isFirstRow && sceneIndex < SceneManager.sceneCount - 1) 540 | sceneIndex++; 541 | currentScene = SceneManager.GetSceneAt(sceneIndex); 542 | } 543 | 544 | RenameSceneInHierarchy(); 545 | 546 | if (settings.displayRowBackground) 547 | { 548 | if (deepestRow != rowItem.rowIndex) 549 | DisplayRowBackground(); 550 | } 551 | 552 | previousElement = rowItem; 553 | previousRowIndex = rowItem.rowIndex; 554 | previousScene = currentScene; 555 | 556 | if (previousRowIndex > deepestRow) 557 | deepestRow = previousRowIndex; 558 | return; 559 | } 560 | else 561 | { 562 | if (rowItem.isFirstElement) 563 | { 564 | if (deepestRow > previousRowIndex) 565 | deepestRow = previousRowIndex; 566 | deepestRow -= rowItem.rowIndex; 567 | 568 | if (IsMultiScene) 569 | { 570 | if (!previousElement.isNull) 571 | { 572 | for (int i = 0; i < SceneManager.sceneCount; ++i) 573 | { 574 | if (SceneManager.GetSceneAt(i) == rowItem.gameObject.scene) 575 | { 576 | sceneIndex = i; 577 | break; 578 | } 579 | } 580 | } 581 | } 582 | } 583 | 584 | if (IsMultiScene) 585 | { 586 | } 587 | 588 | rowItem.nameRect = rowItem.rect; 589 | GUIStyle nameStyle = TreeStyleFromFont(FontStyle.Normal); 590 | rowItem.nameRect.width = nameStyle.CalcSize(new GUIContent(rowItem.gameObject.name)).x; 591 | 592 | rowItem.nameRect.x += 16; 593 | 594 | bool isPrefab = PrefabUtility.IsPartOfPrefabAsset(rowItem.gameObject); 595 | bool isInstance = PrefabUtility.IsPartOfPrefabInstance(rowItem.gameObject); 596 | bool isPrefabParent = PrefabUtility.IsAnyPrefabInstanceRoot(rowItem.gameObject); 597 | bool isPrefabMode = PrefabStageUtility.GetCurrentPrefabStage() != null ? true : false; 598 | 599 | if (settings.displayRowBackground && deepestRow != rowItem.rowIndex) 600 | { 601 | if (isPrefabMode) 602 | { 603 | if (rowItem.gameObject.transform.parent == null) //Should use row index instead. 604 | { 605 | if (deepestRow != 0) 606 | DisplayRowBackground(); 607 | } 608 | } 609 | else 610 | DisplayRowBackground(); 611 | } 612 | 613 | if (settings.useInstantBackground) 614 | CustomRowBackground(); 615 | 616 | if (settings.displayTreeView && !rowItem.isRootObject) 617 | DisplayTreeView(); 618 | 619 | if (settings.displayCustomObjectIcon) 620 | DisplayCustomObjectIcon(null); 621 | 622 | widthUse = WidthUse.zero; 623 | widthUse.left += GLOBAL_SPACE_OFFSET_LEFT; 624 | if (isPrefabMode) widthUse.left -= 2; 625 | widthUse.afterName = rowItem.nameRect.x + rowItem.nameRect.width; 626 | 627 | widthUse.afterName += settings.offSetIconAfterName; 628 | 629 | DisplayEditableIcon(); 630 | 631 | //DisplayNoteIcon(); 632 | 633 | widthUse.afterName += 8; 634 | 635 | if(isInstance && isPrefabParent) 636 | widthUse.right += 14; 637 | 638 | if (settings.displayTag && !rowItem.gameObject.CompareTag("Untagged")) 639 | { 640 | if (!settings.onlyDisplayWhileMouseEnter || 641 | (settings.contentDisplay & HierarchySettings.ContentDisplay.Tag) != 642 | HierarchySettings.ContentDisplay.Tag || 643 | ((settings.contentDisplay & HierarchySettings.ContentDisplay.Tag) == 644 | HierarchySettings.ContentDisplay.Tag && rowItem.isMouseHovering)) 645 | { 646 | DisplayTag(); 647 | } 648 | } 649 | 650 | if (settings.displayLayer && rowItem.gameObject.layer != 0) 651 | { 652 | if (!settings.onlyDisplayWhileMouseEnter || 653 | (settings.contentDisplay & HierarchySettings.ContentDisplay.Layer) != 654 | HierarchySettings.ContentDisplay.Layer || 655 | ((settings.contentDisplay & HierarchySettings.ContentDisplay.Layer) == 656 | HierarchySettings.ContentDisplay.Layer && rowItem.isMouseHovering)) 657 | { 658 | DisplayLayer(); 659 | } 660 | } 661 | 662 | if (settings.displayComponents) 663 | { 664 | if (!settings.onlyDisplayWhileMouseEnter || 665 | (settings.contentDisplay & HierarchySettings.ContentDisplay.Component) != 666 | HierarchySettings.ContentDisplay.Component || 667 | ((settings.contentDisplay & HierarchySettings.ContentDisplay.Component) == 668 | HierarchySettings.ContentDisplay.Component && rowItem.isMouseHovering)) 669 | { 670 | DisplayComponents(); 671 | } 672 | } 673 | 674 | ElementEvent(rowItem); 675 | 676 | FINISH: 677 | if (settings.displayGrid) 678 | DisplayGrid(); 679 | 680 | previousElement = rowItem; 681 | previousRowIndex = rowItem.rowIndex; 682 | previousScene = currentScene; 683 | 684 | if (previousRowIndex > deepestRow) 685 | { 686 | deepestRow = previousRowIndex; 687 | } 688 | } 689 | } 690 | 691 | GUIStyle TreeStyleFromFont(FontStyle fontStyle) 692 | { 693 | GUIStyle style; 694 | switch (fontStyle) 695 | { 696 | case FontStyle.Bold: 697 | style = new GUIStyle(Styles.TreeBoldLabel); 698 | break; 699 | 700 | case FontStyle.Italic: 701 | style = new GUIStyle(Styles.TreeLabel); 702 | break; 703 | 704 | case FontStyle.BoldAndItalic: 705 | style = new GUIStyle(Styles.TreeBoldLabel); 706 | break; 707 | 708 | default: 709 | style = new GUIStyle(Styles.TreeLabel); 710 | break; 711 | } 712 | 713 | return style; 714 | } 715 | 716 | void CustomRowBackground() 717 | { 718 | if (currentEvent.type != EventType.Repaint) 719 | return; 720 | 721 | HierarchySettings.InstantBackgroundColor instantBackgroundColor = new HierarchySettings.InstantBackgroundColor(); 722 | bool contain = false; 723 | for (int i = 0; i < settings.instantBackgroundColors.Count; ++i) 724 | { 725 | if (!settings.instantBackgroundColors[i].active) continue; 726 | if 727 | ( 728 | (settings.instantBackgroundColors[i].useTag && !string.IsNullOrEmpty(settings.instantBackgroundColors[i].tag) && rowItem.gameObject.CompareTag(settings.instantBackgroundColors[i].tag)) || 729 | (settings.instantBackgroundColors[i].useLayer && (1 << rowItem.gameObject.layer & settings.instantBackgroundColors[i].layer) != 0) || 730 | (settings.instantBackgroundColors[i].useStartWith && !string.IsNullOrEmpty(settings.instantBackgroundColors[i].startWith) && rowItem.name.StartsWith(settings.instantBackgroundColors[i].startWith)) 731 | ) 732 | { 733 | contain = true; 734 | instantBackgroundColor = settings.instantBackgroundColors[i]; 735 | } 736 | } 737 | 738 | if (!contain) return; 739 | Color guiColor = GUI.color; 740 | GUI.color = instantBackgroundColor.color; 741 | Rect rect; 742 | var texture = Resources.PixelWhite; 743 | rect = RectFromRight(rowItem.rect, rowItem.rect.width + 16, 0); 744 | rect.x += 16; 745 | rect.xMin = 32; 746 | 747 | GUI.DrawTexture(rect, texture, ScaleMode.StretchToFill); 748 | GUI.color = guiColor; 749 | } 750 | 751 | void ElementEvent(RowItem element) 752 | { 753 | if (currentEvent.type == EventType.KeyDown) 754 | { 755 | if (currentEvent.control && currentEvent.shift && currentEvent.alt && 756 | currentEvent.keyCode == KeyCode.C && lastInteractedHierarchyWindowDelegate() != null) 757 | CollapseAll(); 758 | } 759 | 760 | if (currentEvent.type == EventType.KeyUp && 761 | currentEvent.keyCode == KeyCode.F2 && 762 | Selection.gameObjects.Length > 1) 763 | { 764 | var window = SelectionsRenamePopup.ShowPopup(); 765 | currentEvent.Use(); 766 | return; 767 | } 768 | 769 | if (element.rect.Contains(currentEvent.mousePosition) && currentEvent.type == EventType.MouseUp && 770 | currentEvent.button == 2) 771 | { 772 | Undo.RegisterCompleteObjectUndo(element.gameObject, 773 | element.gameObject.activeSelf ? "Inactive object" : "Active object"); 774 | element.gameObject.SetActive(!element.gameObject.activeSelf); 775 | currentEvent.Use(); 776 | return; 777 | } 778 | } 779 | 780 | void StaticIcon(RowItem element) 781 | { 782 | if (!element.isStatic) return; 783 | 784 | var rect = element.rect; 785 | rect = RectFromRight(rect, 3, 0); 786 | 787 | if (currentEvent.type == EventType.MouseUp && 788 | currentEvent.button == 1 && 789 | rect.Contains(currentEvent.mousePosition)) 790 | { 791 | GenericMenu staticMenu = new GenericMenu(); 792 | staticMenu.AddItem(new GUIContent("Apply All Children"), settings.applyStaticTargetAndChild, 793 | () => { settings.applyStaticTargetAndChild = !settings.applyStaticTargetAndChild; }); 794 | staticMenu.AddItem(new GUIContent("True"), element.gameObject.isStatic ? true : false, 795 | () => { element.gameObject.isStatic = !element.gameObject.isStatic; }); 796 | staticMenu.AddItem(new GUIContent("False"), !element.gameObject.isStatic ? true : false, 797 | () => { element.gameObject.isStatic = !element.gameObject.isStatic; }); 798 | staticMenu.ShowAsContext(); 799 | currentEvent.Use(); 800 | } 801 | } 802 | 803 | void ApplyStaticTargetAndChild(Transform target, bool value) 804 | { 805 | target.gameObject.isStatic = value; 806 | 807 | for (int i = 0; i < target.childCount; ++i) 808 | ApplyStaticTargetAndChild(target.GetChild(i), value); 809 | } 810 | 811 | void DisplayCustomObjectIcon(Texture icon) 812 | { 813 | var rect = RectFromRight(rowItem.nameRect, 16, rowItem.nameRect.width + 1); 814 | rect.height = 16; 815 | 816 | if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 && 817 | rect.Contains(currentEvent.mousePosition)) 818 | { 819 | IconSelectorShowAtPositionDelegate(rowItem.gameObject, rect, true); 820 | currentEvent.Use(); 821 | } 822 | 823 | if (currentEvent.type == EventType.Repaint) 824 | { 825 | if (rect.Contains(currentEvent.mousePosition)) 826 | { 827 | } 828 | 829 | if (icon == null) 830 | { 831 | icon = AssetPreview.GetMiniThumbnail(rowItem.gameObject); 832 | if (icon.name == "GameObject Icon" || icon.name == "d_GameObject Icon" || icon.name == "Prefab Icon" || 833 | icon.name == "d_Prefab Icon" || icon.name == "PrefabModel Icon" || 834 | icon.name == "d_PrefabModel Icon") 835 | return; 836 | } 837 | 838 | Color guiColor = GUI.color; 839 | GUI.color = rowItem.rowIndex % 2 != 0 ? ThemeData.colorRowEven : ThemeData.colorRowOdd; 840 | GUI.DrawTexture(rect, Resources.PixelWhite); 841 | GUI.color = guiColor; 842 | GUI.DrawTexture(rect, icon, ScaleMode.ScaleToFit); 843 | } 844 | } 845 | 846 | void DisplayEditableIcon() 847 | { 848 | if (rowItem.gameObject.hideFlags == HideFlags.NotEditable) 849 | { 850 | Rect lockRect = RectFromLeft(rowItem.nameRect, 12, ref widthUse.afterName); 851 | 852 | if (currentEvent.type == EventType.Repaint) 853 | { 854 | GUI.color = ThemeData.colorLockIcon; 855 | GUI.DrawTexture(lockRect, Resources.lockIconOn, ScaleMode.ScaleToFit); 856 | GUI.color = Color.white; 857 | } 858 | 859 | if (currentEvent.type == EventType.MouseUp && 860 | currentEvent.button == 1 && 861 | lockRect.Contains(currentEvent.mousePosition)) 862 | { 863 | GenericMenu lockMenu = new GenericMenu(); 864 | 865 | GameObject gameObject = rowItem.gameObject; 866 | 867 | lockMenu.AddItem(new GUIContent("Unlock"), false, () => 868 | { 869 | Undo.RegisterCompleteObjectUndo(gameObject, "Unlock..."); 870 | foreach (Component component in gameObject.GetComponents()) 871 | { 872 | if (component) 873 | { 874 | Undo.RegisterCompleteObjectUndo(component, "Unlock..."); 875 | component.hideFlags = HideFlags.None; 876 | } 877 | } 878 | 879 | gameObject.hideFlags = HideFlags.None; 880 | 881 | InternalEditorUtility.RepaintAllViews(); 882 | }); 883 | lockMenu.ShowAsContext(); 884 | currentEvent.Use(); 885 | } 886 | } 887 | } 888 | 889 | void DisplayComponents() 890 | { 891 | var components = rowItem.gameObject.GetComponents(typeof(Component)).ToList(); 892 | var rendererComponent = rowItem.gameObject.GetComponent(); 893 | bool hasMaterial = rendererComponent != null && rendererComponent.sharedMaterial != null; 894 | 895 | if (hasMaterial) 896 | { 897 | for (int i = 0; i < rendererComponent.sharedMaterials.Length; ++i) 898 | { 899 | Material sharedMat = rendererComponent.sharedMaterials[i]; 900 | components.Add(sharedMat); 901 | } 902 | } 903 | 904 | int length = components.Count; 905 | float widthUsedCached = 0; 906 | widthUse.right -= 16; 907 | if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName) 908 | { 909 | widthUsedCached = widthUse.afterName; 910 | widthUse.afterName += 4; 911 | } 912 | else 913 | { 914 | widthUsedCached = widthUse.right; 915 | widthUse.right += 2; 916 | } 917 | 918 | for (int i = 0; i < length; ++i) 919 | { 920 | var component = components[i]; 921 | 922 | try 923 | { 924 | Type comType = component.GetType(); 925 | 926 | if (comType != null) 927 | { 928 | bool isMono = false; 929 | if (comType.BaseType == typeof(MonoBehaviour)) isMono = true; 930 | if (isMono) 931 | { 932 | //TODO: ??? 933 | bool shouldIgnoreThisMono = false; 934 | if (shouldIgnoreThisMono) continue; 935 | } 936 | 937 | switch (settings.componentDisplayMode) 938 | { 939 | case HierarchySettings.ComponentDisplayMode.ScriptOnly: 940 | if (!isMono) 941 | continue; 942 | break; 943 | 944 | case HierarchySettings.ComponentDisplayMode.Specified: 945 | if (!dicComponents.ContainsKey(comType.Name)) 946 | continue; 947 | break; 948 | 949 | case HierarchySettings.ComponentDisplayMode.Ignore: 950 | if (dicComponents.ContainsKey(comType.Name)) 951 | continue; 952 | break; 953 | } 954 | 955 | Rect rect = Rect.zero; 956 | 957 | if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName) 958 | rect = RectFromLeft(rowItem.nameRect, settings.componentSize, ref widthUse.afterName); 959 | else 960 | rect = RectFromRight(rowItem.rect, settings.componentSize, ref widthUse.right); 961 | 962 | 963 | if (hasMaterial && i == length - rendererComponent.sharedMaterials.Length && 964 | settings.componentDisplayMode != HierarchySettings.ComponentDisplayMode.ScriptOnly) 965 | { 966 | for (int m = 0; m < rendererComponent.sharedMaterials.Length; ++m) 967 | { 968 | var sharedMaterial = rendererComponent.sharedMaterials[m]; 969 | 970 | if (sharedMaterial == null) continue; 971 | ComponentIcon(sharedMaterial, comType, rect, true); 972 | 973 | if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName) 974 | rect = RectFromLeft(rowItem.nameRect, settings.componentSize, 975 | ref widthUse.afterName); 976 | else 977 | rect = RectFromRight(rowItem.rect, settings.componentSize, ref widthUse.right); 978 | } 979 | 980 | break; 981 | } 982 | 983 | ComponentIcon(component, comType, rect); 984 | 985 | if (settings.componentAlignment == HierarchySettings.ElementAlignment.AfterName) 986 | widthUse.afterName += settings.componentSpacing; 987 | else 988 | widthUse.right += settings.componentSpacing; 989 | } 990 | } 991 | catch (System.Exception) 992 | { 993 | continue; 994 | } 995 | } 996 | } 997 | 998 | void ComponentIcon(UnityEngine.Object component, Type componentType, Rect rect, bool isMaterial = false) 999 | { 1000 | int comHash = component.GetHashCode(); 1001 | 1002 | if (currentEvent.type == EventType.Repaint) 1003 | { 1004 | Texture image = EditorGUIUtility.ObjectContent(component, componentType).image; 1005 | 1006 | if (selectedComponents.ContainsKey(comHash)) 1007 | { 1008 | Color guiColor = GUI.color; 1009 | GUI.color = ThemeData.comSelBGColor; 1010 | GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill); 1011 | GUI.color = guiColor; 1012 | } 1013 | 1014 | string tooltip = isMaterial ? component.name : componentType.Name; 1015 | tooltipContent.tooltip = tooltip; 1016 | GUI.Box(rect, tooltipContent, GUIStyle.none); 1017 | 1018 | GUI.DrawTexture(rect, image, ScaleMode.ScaleToFit); 1019 | } 1020 | 1021 | 1022 | if (rect.Contains(currentEvent.mousePosition)) 1023 | { 1024 | if (currentEvent.type == EventType.MouseDown) 1025 | { 1026 | if (currentEvent.button == 0) 1027 | { 1028 | if (currentEvent.control) 1029 | { 1030 | if (!selectedComponents.ContainsKey(comHash)) 1031 | { 1032 | selectedComponents.Add(comHash, component); 1033 | activeComponent = component; 1034 | } 1035 | else 1036 | { 1037 | selectedComponents.Remove(comHash); 1038 | } 1039 | 1040 | currentEvent.Use(); 1041 | return; 1042 | } 1043 | 1044 | selectedComponents.Clear(); 1045 | selectedComponents.Add(comHash, component); 1046 | activeComponent = component; 1047 | currentEvent.Use(); 1048 | return; 1049 | } 1050 | 1051 | if (currentEvent.button == 1) 1052 | { 1053 | if (currentEvent.control) 1054 | { 1055 | GenericMenu componentGenericMenu = new GenericMenu(); 1056 | 1057 | componentGenericMenu.AddItem(new GUIContent("Remove All Component"), false, () => 1058 | { 1059 | if (!selectedComponents.ContainsKey(comHash)) 1060 | selectedComponents.Add(comHash, component); 1061 | 1062 | foreach (var selectedComponent in selectedComponents.ToList()) 1063 | { 1064 | if (selectedComponent.Value is Material) 1065 | continue; 1066 | 1067 | selectedComponents.Remove(selectedComponent.Key); 1068 | Undo.DestroyObjectImmediate(selectedComponent.Value); 1069 | } 1070 | 1071 | selectedComponents.Clear(); 1072 | }); 1073 | componentGenericMenu.ShowAsContext(); 1074 | } 1075 | else 1076 | { 1077 | DisplayObjectContextMenuDelegate(rect, component, 0); 1078 | } 1079 | 1080 | currentEvent.Use(); 1081 | return; 1082 | } 1083 | } 1084 | 1085 | if (currentEvent.type == EventType.MouseUp) 1086 | { 1087 | if (currentEvent.button == 0) 1088 | { 1089 | List inspectorComponents = new List(); 1090 | 1091 | foreach (var selectedComponent in selectedComponents) 1092 | inspectorComponents.Add(selectedComponent.Value); 1093 | 1094 | if (!selectedComponents.ContainsKey(comHash)) 1095 | inspectorComponents.Add(component); 1096 | 1097 | var window = QuickInspect.OpenEditor(); 1098 | window.Fill(inspectorComponents, 1099 | currentEvent.alt ? QuickInspect.FillMode.Add : QuickInspect.FillMode.Default); 1100 | window.Focus(); 1101 | 1102 | currentEvent.Use(); 1103 | return; 1104 | } 1105 | } 1106 | } 1107 | 1108 | if (selectedComponents.Count > 0 && 1109 | currentEvent.type == EventType.MouseDown && 1110 | currentEvent.button == 0 && 1111 | !currentEvent.control && 1112 | !rect.Contains(currentEvent.mousePosition)) 1113 | { 1114 | selectedComponents.Clear(); 1115 | activeComponent = null; 1116 | } 1117 | } 1118 | 1119 | void DisplayTag() 1120 | { 1121 | GUIContent tagContent = new GUIContent(rowItem.gameObject.tag); 1122 | 1123 | var style = Styles.Tag; 1124 | style.normal.textColor = ThemeData.tagColor; 1125 | Rect rect; 1126 | 1127 | if (settings.tagAlignment == HierarchySettings.ElementAlignment.AfterName) 1128 | { 1129 | rect = RectFromLeft(rowItem.nameRect, style.CalcSize(tagContent).x, ref widthUse.afterName); 1130 | 1131 | if (currentEvent.type == EventType.Repaint) 1132 | { 1133 | GUI.Label(rect, tagContent, style); 1134 | } 1135 | } 1136 | else 1137 | { 1138 | rect = RectFromRight(rowItem.rect, style.CalcSize(tagContent).x, ref widthUse.right); 1139 | 1140 | if (currentEvent.type == EventType.Repaint) 1141 | { 1142 | GUI.Label(rect, tagContent, style); 1143 | } 1144 | } 1145 | 1146 | if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 && 1147 | rect.Contains(currentEvent.mousePosition)) 1148 | { 1149 | GenericMenu menuTags = new GenericMenu(); 1150 | GameObject gameObject = rowItem.gameObject; 1151 | 1152 | menuTags.AddItem(new GUIContent("Apply All Children"), settings.applyTagTargetAndChild, 1153 | () => { settings.applyTagTargetAndChild = !settings.applyTagTargetAndChild; }); 1154 | 1155 | foreach (var tag in InternalEditorUtility.tags) 1156 | { 1157 | menuTags.AddItem(new GUIContent(tag), gameObject.tag == tag ? true : false, () => 1158 | { 1159 | if (settings.applyTagTargetAndChild) 1160 | ApplyTagTargetAndChild(gameObject.transform, tag); 1161 | else 1162 | { 1163 | Undo.RegisterCompleteObjectUndo(gameObject, "Change Tag"); 1164 | gameObject.tag = tag; 1165 | } 1166 | }); 1167 | } 1168 | 1169 | menuTags.ShowAsContext(); 1170 | currentEvent.Use(); 1171 | } 1172 | } 1173 | 1174 | void ApplyTagTargetAndChild(Transform target, string tag) 1175 | { 1176 | Undo.RegisterCompleteObjectUndo(target.gameObject, "Change Tag"); 1177 | target.gameObject.tag = tag; 1178 | 1179 | for (int i = 0; i < target.childCount; ++i) 1180 | ApplyTagTargetAndChild(target.GetChild(i), tag); 1181 | } 1182 | 1183 | void DisplayLayer() 1184 | { 1185 | GUIContent layerContent = new GUIContent(LayerMask.LayerToName(rowItem.gameObject.layer)); 1186 | var style = Styles.Layer; 1187 | style.normal.textColor = ThemeData.layerColor; 1188 | Rect rect; 1189 | 1190 | if (settings.layerAlignment == HierarchySettings.ElementAlignment.AfterName) 1191 | { 1192 | rect = RectFromLeft(rowItem.nameRect, style.CalcSize(layerContent).x, ref widthUse.afterName); 1193 | 1194 | if (currentEvent.type == EventType.Repaint) 1195 | { 1196 | GUI.Label(rect, layerContent, style); 1197 | } 1198 | } 1199 | else 1200 | { 1201 | rect = RectFromRight(rowItem.rect, style.CalcSize(layerContent).x, ref widthUse.right); 1202 | 1203 | if (currentEvent.type == EventType.Repaint) 1204 | { 1205 | GUI.Label(rect, layerContent, style); 1206 | } 1207 | } 1208 | 1209 | if (currentEvent.type == EventType.MouseUp && currentEvent.button == 1 && 1210 | rect.Contains(currentEvent.mousePosition)) 1211 | { 1212 | GenericMenu menuLayers = new GenericMenu(); 1213 | GameObject gameObject = rowItem.gameObject; 1214 | 1215 | menuLayers.AddItem(new GUIContent("Apply All Children"), settings.applyLayerTargetAndChild, 1216 | () => { settings.applyLayerTargetAndChild = !settings.applyLayerTargetAndChild; }); 1217 | 1218 | foreach (string layer in InternalEditorUtility.layers) 1219 | { 1220 | menuLayers.AddItem(new GUIContent(layer), 1221 | LayerMask.NameToLayer(layer) == gameObject.layer ? true : false, () => 1222 | { 1223 | if (settings.applyLayerTargetAndChild) 1224 | ApplyLayerTargetAndChild(gameObject.transform, LayerMask.NameToLayer(layer)); 1225 | else 1226 | { 1227 | Undo.RegisterCompleteObjectUndo(gameObject, "Change Layer"); 1228 | gameObject.layer = LayerMask.NameToLayer(layer); 1229 | } 1230 | }); 1231 | } 1232 | 1233 | menuLayers.ShowAsContext(); 1234 | currentEvent.Use(); 1235 | } 1236 | } 1237 | 1238 | void ApplyLayerTargetAndChild(Transform target, int layer) 1239 | { 1240 | Undo.RegisterCompleteObjectUndo(target.gameObject, "Change Layer"); 1241 | target.gameObject.layer = layer; 1242 | 1243 | for (int i = 0; i < target.childCount; ++i) 1244 | ApplyLayerTargetAndChild(target.GetChild(i), layer); 1245 | } 1246 | 1247 | void DisplayRowBackground(bool nextRow = true) 1248 | { 1249 | if (currentEvent.type != EventType.Repaint) 1250 | return; 1251 | 1252 | Rect rect = rowItem.rect; 1253 | rect.xMin = -1; 1254 | rect.width += 16; 1255 | 1256 | Color color = (rect.y / rect.height) % 2 == 0 ? ThemeData.colorRowEven : ThemeData.colorRowOdd; 1257 | 1258 | if (nextRow) 1259 | rect.y += rect.height; 1260 | 1261 | Color guiColor = GUI.color; 1262 | GUI.color = color; 1263 | GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill); 1264 | GUI.color = guiColor; 1265 | } 1266 | 1267 | void DisplayGrid() 1268 | { 1269 | if (currentEvent.type != EventType.Repaint) 1270 | return; 1271 | 1272 | var rect = rowItem.rect; 1273 | 1274 | rect.xMin = GLOBAL_SPACE_OFFSET_LEFT; 1275 | rect.y += 15; 1276 | rect.width += 16; 1277 | rect.height = 1; 1278 | 1279 | Color guiColor = GUI.color; 1280 | GUI.color = ThemeData.colorGrid; 1281 | GUI.DrawTexture(rect, Resources.PixelWhite, ScaleMode.StretchToFill); 1282 | GUI.color = guiColor; 1283 | } 1284 | 1285 | void DisplayTreeView() 1286 | { 1287 | if (currentEvent.type != EventType.Repaint) 1288 | return; 1289 | 1290 | Rect rect = rowItem.rect; 1291 | 1292 | rect.width = 40; 1293 | rect.x -= 34; 1294 | var t = rowItem.gameObject.transform.parent; 1295 | 1296 | Color guiColor = GUI.color; 1297 | GUI.color = ThemeData.colorTreeView; 1298 | 1299 | if (t.childCount == 1 || t.GetChild(t.childCount - 1) == rowItem.gameObject.transform) 1300 | { 1301 | GUI.DrawTexture(rect, resources.GetIcon("icon_branch_L"), ScaleMode.ScaleToFit); 1302 | } 1303 | else 1304 | { 1305 | GUI.DrawTexture(rect, resources.GetIcon("icon_branch_T"), ScaleMode.ScaleToFit); 1306 | } 1307 | 1308 | while (t != null) 1309 | { 1310 | if (t.parent == null) 1311 | break; 1312 | 1313 | if (t == t.parent.GetChild(t.parent.childCount - 1)) 1314 | { 1315 | t = t.parent; 1316 | rect.x -= 14; 1317 | continue; 1318 | } 1319 | 1320 | rect.x -= 14; 1321 | GUI.DrawTexture(rect, resources.GetIcon("icon_branch_I"), ScaleMode.ScaleToFit); 1322 | t = t.parent; 1323 | } 1324 | 1325 | GUI.color = guiColor; 1326 | } 1327 | 1328 | GUIContent tmpSceneContent = new GUIContent(); 1329 | 1330 | void RenameSceneInHierarchy() 1331 | { 1332 | string name = currentScene.name; 1333 | if (name == "") 1334 | return; 1335 | 1336 | var leftTitleWidthUsed = 48f; 1337 | #if UNITY_2019_1_OR_NEWER 1338 | leftTitleWidthUsed += 24f; 1339 | #endif 1340 | 1341 | if (!currentScene.isLoaded) 1342 | name = string.Format("{0} (not loaded", name); 1343 | 1344 | tmpSceneContent.text = name == "" ? "Untitled" : name; 1345 | Vector2 size = Styles.TreeBoldLabel.CalcSize(tmpSceneContent); 1346 | leftTitleWidthUsed += size.x; 1347 | 1348 | 1349 | if (currentEvent.type == EventType.KeyDown && 1350 | currentEvent.keyCode == KeyCode.F2 && 1351 | rowItem.rect.Contains(currentEvent.mousePosition)) 1352 | { 1353 | SceneRenamePopup.ShowPopup(currentScene); 1354 | } 1355 | } 1356 | 1357 | void CollapseAll() 1358 | { 1359 | } 1360 | 1361 | void DirtyScene(Scene scene) 1362 | { 1363 | if (EditorApplication.isPlaying) 1364 | return; 1365 | 1366 | EditorSceneManager.MarkSceneDirty(scene); 1367 | } 1368 | 1369 | bool IsFirstElement(Rect rect) => previousRowIndex > rect.y / rect.height; 1370 | 1371 | bool IsFirstRow(Rect rect) => rect.y / rect.height == 0; 1372 | 1373 | int GetRowIndex(Rect rect) => (int)(rect.y / rect.height); 1374 | 1375 | bool InSelection(int ID) => Selection.Contains(ID) ? true : false; 1376 | 1377 | bool IsElementDirty(int ID) => EditorUtility.IsDirty(ID); 1378 | 1379 | Rect RectFromRight(Rect rect, float width, float usedWidth) 1380 | { 1381 | usedWidth += width; 1382 | rect.x = rect.x + rect.width - usedWidth; 1383 | rect.width = width; 1384 | return rect; 1385 | } 1386 | 1387 | Rect RectFromRight(Rect rect, float width, ref float usedWidth) 1388 | { 1389 | usedWidth += width; 1390 | rect.x = rect.x + rect.width - usedWidth; 1391 | rect.width = width; 1392 | return rect; 1393 | } 1394 | 1395 | Rect RectFromRight(Rect rect, Vector2 offset, float width, ref float usedWidth) 1396 | { 1397 | usedWidth += width; 1398 | rect.position += offset; 1399 | rect.x = rect.x + rect.width - usedWidth; 1400 | rect.width = width; 1401 | return rect; 1402 | } 1403 | 1404 | Rect RectFromLeft(Rect rect, float width, float usedWidth, bool usexmin = true) 1405 | { 1406 | if (usexmin) 1407 | rect.xMin = 0; 1408 | rect.x += usedWidth; 1409 | rect.width = width; 1410 | usedWidth += width; 1411 | return rect; 1412 | } 1413 | 1414 | Rect RectFromLeft(Rect rect, float width, ref float usedWidth, bool usexmin = true) 1415 | { 1416 | if (usexmin) 1417 | rect.xMin = 0; 1418 | rect.x += usedWidth; 1419 | rect.width = width; 1420 | usedWidth += width; 1421 | return rect; 1422 | } 1423 | 1424 | Rect RectFromLeft(Rect rect, Vector2 offset, float width, ref float usedWidth, bool usexmin = true) 1425 | { 1426 | if (usexmin) 1427 | rect.xMin = 0; 1428 | rect.position += offset; 1429 | rect.x += usedWidth; 1430 | rect.width = width; 1431 | usedWidth += width; 1432 | return rect; 1433 | } 1434 | 1435 | struct WidthUse 1436 | { 1437 | public float left; 1438 | public float right; 1439 | public float afterName; 1440 | 1441 | public WidthUse(float left, float right, float afterName) 1442 | { 1443 | this.left = left; 1444 | this.right = right; 1445 | this.afterName = afterName; 1446 | } 1447 | 1448 | public static WidthUse zero 1449 | { 1450 | get { return new WidthUse(0, 0, 0); } 1451 | } 1452 | } 1453 | 1454 | } 1455 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08cb8ab4ed87d60439f82d715b16a0af 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyResources.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEditor; 6 | 7 | namespace Quartzified.Tools.Hierarchy 8 | { 9 | [CreateAssetMenu(fileName = "Hierarchy Resource", menuName = "Quartzified/Editor/Hierarchy/Hierarchy Resource")] 10 | internal class HierarchyResources : ScriptableObject 11 | { 12 | Dictionary dicIcons = new Dictionary(); 13 | public List listIcons = new List(); 14 | 15 | public void GenerateKeyForAssets() 16 | { 17 | dicIcons.Clear(); 18 | dicIcons = listIcons.ToDictionary(texture2D => texture2D.name); 19 | } 20 | 21 | public Texture2D GetIcon(string key) 22 | { 23 | Texture2D texture2D = null; 24 | var getResult = dicIcons.TryGetValue(key, out texture2D); 25 | if (getResult == false) 26 | Debug.Log(string.Format("Icon with {0} not found, return null.", key)); 27 | return texture2D; 28 | } 29 | 30 | internal static HierarchyResources GetAssets() 31 | { 32 | var guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(HierarchyResources).Name)); 33 | 34 | if (guids.Length > 0) 35 | { 36 | var asset = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[0])); 37 | if (asset != null) 38 | return asset; 39 | } 40 | 41 | return null; 42 | } 43 | 44 | internal static HierarchyResources CreateAssets() 45 | { 46 | String path = EditorUtility.SaveFilePanelInProject("Save as...", "Resources", "asset", ""); 47 | if (path.Length > 0) 48 | { 49 | HierarchyResources settings = ScriptableObject.CreateInstance(); 50 | AssetDatabase.CreateAsset(settings, path); 51 | AssetDatabase.SaveAssets(); 52 | AssetDatabase.Refresh(); 53 | EditorUtility.FocusProjectWindow(); 54 | Selection.activeObject = settings; 55 | return settings; 56 | } 57 | 58 | return null; 59 | } 60 | } 61 | 62 | [CustomEditor(typeof(HierarchyResources))] 63 | internal class ResourcesInspector : Editor 64 | { 65 | HierarchyResources resources; 66 | 67 | void OnEnable() => resources = target as HierarchyResources; 68 | 69 | public override void OnInspectorGUI() 70 | { 71 | DrawDefaultInspector(); 72 | if (GUILayout.Button("Generate Key For Assets")) 73 | resources.GenerateKeyForAssets(); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyResources.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 69af6b3b1c5f59247bb9c330c0823d71 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchySettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using System.IO; 6 | 7 | namespace Quartzified.Tools.Hierarchy 8 | { 9 | [Serializable] 10 | internal class HierarchySettings : ScriptableObject 11 | { 12 | [Serializable] 13 | public struct ThemeData 14 | { 15 | public Color colorRowEven; 16 | public Color colorRowOdd; 17 | public Color colorGrid; 18 | public Color colorTreeView; 19 | public Color colorLockIcon; 20 | public Color tagColor; 21 | public Color layerColor; 22 | public Color comSelBGColor; 23 | public Color selectionColor; 24 | 25 | public ThemeData(ThemeData themeData) 26 | { 27 | colorRowEven = themeData.colorRowEven; 28 | colorRowOdd = themeData.colorRowOdd; 29 | colorGrid = themeData.colorGrid; 30 | colorTreeView = themeData.colorTreeView; 31 | colorLockIcon = themeData.colorLockIcon; 32 | tagColor = themeData.tagColor; 33 | layerColor = themeData.layerColor; 34 | comSelBGColor = themeData.comSelBGColor; 35 | selectionColor = themeData.selectionColor; 36 | } 37 | 38 | public void BlendMultiply(Color blend) 39 | { 40 | colorRowEven = colorRowEven * blend; 41 | colorRowOdd = colorRowOdd * blend; 42 | colorGrid = colorGrid * blend; 43 | colorTreeView = colorTreeView * blend; 44 | colorLockIcon = colorLockIcon * blend; 45 | tagColor = tagColor * blend; 46 | layerColor = layerColor * blend; 47 | comSelBGColor = comSelBGColor * blend; 48 | selectionColor = selectionColor * blend; 49 | } 50 | } 51 | 52 | [Serializable] 53 | public class HeaderTagData 54 | { 55 | public int headerCount; 56 | public List headerTag = new List(); 57 | public List headerColor = new List(); 58 | } 59 | 60 | ///Define background color using prefix. 61 | [Serializable] 62 | public struct InstantBackgroundColor 63 | { 64 | public bool active; 65 | public bool useStartWith, useTag, useLayer; 66 | public string startWith; 67 | public string tag; 68 | public LayerMask layer; 69 | public Color color; 70 | } 71 | 72 | public enum ComponentSize 73 | { 74 | Small, 75 | Normal, 76 | Large 77 | } 78 | 79 | public enum ElementAlignment 80 | { 81 | AfterName, 82 | Right 83 | } 84 | 85 | [Flags] 86 | public enum ContentDisplay 87 | { 88 | Component = (1 << 0), 89 | Tag = (1 << 1), 90 | Layer = (1 << 2) 91 | } 92 | 93 | internal static HierarchySettings instance; 94 | 95 | public ThemeData personalTheme; 96 | public ThemeData professionalTheme; 97 | public ThemeData playmodeTheme; 98 | private bool useThemePlaymode = false; 99 | 100 | public ThemeData usedThemeData 101 | { 102 | get 103 | { 104 | if (EditorApplication.isPlayingOrWillChangePlaymode) 105 | { 106 | if (useThemePlaymode == false) 107 | { 108 | playmodeTheme = new ThemeData(EditorGUIUtility.isProSkin ? professionalTheme : personalTheme); 109 | playmodeTheme.BlendMultiply(GUI.color); 110 | useThemePlaymode = true; 111 | } 112 | 113 | return playmodeTheme; 114 | } 115 | else 116 | { 117 | useThemePlaymode = false; 118 | return EditorGUIUtility.isProSkin ? professionalTheme : personalTheme; 119 | } 120 | } 121 | } 122 | 123 | public HeaderTagData tagData; 124 | 125 | [HideInInspector] public bool activeHierarchy = true; 126 | public bool displayCustomObjectIcon = true; 127 | public bool displayTreeView = true; 128 | public bool displayRowBackground = true; 129 | public bool displayGrid = false; 130 | [HideInInspector] public bool displayStaticButton = true; 131 | public int offSetIconAfterName = 8; 132 | public bool displayComponents = true; 133 | public ElementAlignment componentAlignment = ElementAlignment.AfterName; 134 | 135 | public enum ComponentDisplayMode 136 | { 137 | All = 0, 138 | ScriptOnly = 1, 139 | Specified = 2, 140 | Ignore = 3 141 | } 142 | 143 | public ComponentDisplayMode componentDisplayMode = ComponentDisplayMode.Ignore; 144 | public string[] components = new string[] {"Transform", "RectTransform"}; 145 | [HideInInspector] public int componentLimited = 0; 146 | [Range(12, 16)] public int componentSize = 16; 147 | public int componentSpacing = 0; 148 | public bool displayTag = true; 149 | public ElementAlignment tagAlignment = ElementAlignment.AfterName; 150 | public bool displayLayer = true; 151 | public ElementAlignment layerAlignment = ElementAlignment.AfterName; 152 | [HideInInspector] public bool applyStaticTargetAndChild = true; 153 | public bool applyTagTargetAndChild = false; 154 | public bool applyLayerTargetAndChild = true; 155 | public bool useInstantBackground = false; 156 | 157 | public List instantBackgroundColors = new List(); 158 | 159 | public bool onlyDisplayWhileMouseEnter = false; 160 | public ContentDisplay contentDisplay = ContentDisplay.Component | ContentDisplay.Tag | ContentDisplay.Layer; 161 | 162 | 163 | public delegate void OnSettingsChangedCallback(string param); 164 | 165 | public OnSettingsChangedCallback onSettingsChanged; 166 | 167 | public void OnSettingsChanged(string param = "") 168 | { 169 | switch (param) 170 | { 171 | case nameof(componentSize): 172 | if (componentSize % 2 != 0) componentSize -= 1; 173 | break; 174 | 175 | case nameof(componentSpacing): 176 | if (componentSpacing < 0) componentSpacing = 0; 177 | break; 178 | } 179 | 180 | onSettingsChanged?.Invoke(param); 181 | hideFlags = HideFlags.None; 182 | } 183 | 184 | internal static HierarchySettings GetAssets() 185 | { 186 | if (instance != null) 187 | return instance; 188 | 189 | var guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof(HierarchySettings).Name)); 190 | 191 | for (int i = 0; i < guids.Length; i++) 192 | { 193 | instance = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[i])); 194 | if (instance != null) 195 | return instance; 196 | } 197 | 198 | return instance = CreateAssets(); 199 | } 200 | 201 | internal static HierarchySettings CreateAssets() 202 | { 203 | string path = EditorUtility.SaveFilePanelInProject("Save as...", "Hierarchy Settings", "asset", ""); 204 | if (path.Length > 0) 205 | { 206 | HierarchySettings settings = ScriptableObject.CreateInstance(); 207 | AssetDatabase.CreateAsset(settings, path); 208 | AssetDatabase.SaveAssets(); 209 | AssetDatabase.Refresh(); 210 | EditorUtility.FocusProjectWindow(); 211 | Selection.activeObject = settings; 212 | return settings; 213 | } 214 | 215 | return null; 216 | } 217 | 218 | internal bool ImportFromJson() 219 | { 220 | string path = EditorUtility.OpenFilePanel("Import Hierarchy settings", "", "json"); 221 | if (path.Length > 0) 222 | { 223 | string json = string.Empty; 224 | using (StreamReader sr = new StreamReader(path)) 225 | { 226 | json = sr.ReadToEnd(); 227 | } 228 | 229 | if (string.IsNullOrEmpty(json)) return false; 230 | JsonUtility.FromJsonOverwrite(json, this); 231 | AssetDatabase.SaveAssets(); 232 | AssetDatabase.Refresh(); 233 | return true; 234 | } 235 | 236 | return false; 237 | } 238 | 239 | internal TextAsset ExportToJson() 240 | { 241 | string path = EditorUtility.SaveFilePanelInProject("Export Hierarchy settings as...", "Hierarchy Settings", "json", ""); 242 | if (path.Length > 0) 243 | { 244 | string json = JsonUtility.ToJson(instance, true); 245 | using (StreamWriter sw = new StreamWriter(path)) 246 | { 247 | sw.Write(json); 248 | } 249 | 250 | AssetDatabase.SaveAssets(); 251 | AssetDatabase.Refresh(); 252 | EditorUtility.FocusProjectWindow(); 253 | TextAsset asset = AssetDatabase.LoadAssetAtPath(path); 254 | Selection.activeObject = asset; 255 | return asset; 256 | } 257 | 258 | return null; 259 | } 260 | } 261 | 262 | [CustomEditor(typeof(HierarchySettings))] 263 | internal class SettingsInspector : Editor 264 | { 265 | HierarchySettings settings; 266 | 267 | void OnEnable() => settings = target as HierarchySettings; 268 | 269 | public override void OnInspectorGUI() 270 | { 271 | EditorGUILayout.HelpBox("Go to Edit -> Preferences" + 272 | " -> Quartzified /Hierarchy", MessageType.Info); 273 | if (GUILayout.Button("Open Settings")) 274 | SettingsService.OpenUserPreferences("Quartzified/Hierarchy"); 275 | 276 | GUILayout.Space(16); 277 | 278 | EditorGUILayout.HelpBox(" You can Quick Inspect by pressing the Component Icons in the Hierarchy,", MessageType.Info); 279 | EditorGUILayout.HelpBox(" You can quickly update the names of objects by selecting them and pressing F2\n" + 280 | " You can do this in the hierarchy with Scenes or Multiple Objects at once.", MessageType.Info); 281 | 282 | 283 | //base.OnInspectorGUI(); 284 | } 285 | } 286 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchySettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8b7bbe92ee6f2f74ab6bb3656648fd63 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchySettingsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEditor; 5 | using UnityEditor.UIElements; 6 | using UnityEngine; 7 | using UnityEngine.UIElements; 8 | 9 | namespace Quartzified.Tools.Hierarchy 10 | { 11 | public static class HierarchySettingsProvider 12 | { 13 | static HierarchySettings instance => HierarchySettings.instance; 14 | 15 | static float TITLE_MARGIN_TOP = 14; 16 | static float TITLE_MARGIN_BOTTOM = 8; 17 | static float CONTENT_MARGIN_LEFT = 10; 18 | 19 | 20 | [SettingsProvider] 21 | static SettingsProvider SettingsProvider() 22 | { 23 | SettingsProvider provider = new SettingsProvider("Quartzified/Hierarchy", SettingsScope.User) 24 | { 25 | label = "Hierarchy", 26 | 27 | activateHandler = (searchContext, rootElement) => 28 | { 29 | HierarchySettings settings = HierarchySettings.GetAssets(); 30 | 31 | HorizontalLayout horizontalLayout = new HorizontalLayout(); 32 | horizontalLayout.style.backgroundColor = new Color(0, 0, 0, 0.2f); 33 | horizontalLayout.style.paddingTop = 4; 34 | horizontalLayout.style.paddingBottom = 10; 35 | rootElement.Add(horizontalLayout); 36 | 37 | Label hierarchyTitle = new Label("Hierarchy"); 38 | hierarchyTitle.StyleFontSize(20); 39 | hierarchyTitle.StyleMargin(10, 0, 2, 2); 40 | hierarchyTitle.StyleFont(FontStyle.Bold); 41 | horizontalLayout.Add(hierarchyTitle); 42 | 43 | Label importButton = new Label(); 44 | importButton.StyleFontSize(14); 45 | importButton.StyleMargin(0, 0, 6, 0); 46 | importButton.text = " Import"; 47 | importButton.style.unityFontStyleAndWeight = FontStyle.Italic; 48 | Color importExportButtonColor = new Color32(102, 157, 246, 255); 49 | importButton.style.color = importExportButtonColor; 50 | importButton.RegisterCallback(evt => HierarchySettings.instance.ImportFromJson()); 51 | horizontalLayout.Add(importButton); 52 | 53 | Label exportButton = new Label(); 54 | exportButton.StyleFontSize(14); 55 | exportButton.StyleMargin(0, 0, 6, 0); 56 | exportButton.text = "| Export"; 57 | exportButton.style.unityFontStyleAndWeight = FontStyle.Italic; 58 | exportButton.style.color = importExportButtonColor; 59 | exportButton.RegisterCallback(evt => HierarchySettings.instance.ExportToJson()); 60 | horizontalLayout.Add(exportButton); 61 | 62 | ScrollView scrollView = new ScrollView(); 63 | rootElement.Add(scrollView); 64 | 65 | VerticalLayout verticalLayout = new VerticalLayout(); 66 | verticalLayout.StylePadding(8, 8, 8, 8); 67 | scrollView.Add(verticalLayout); 68 | 69 | var Object = new Label("Object"); 70 | Object.StyleFont(FontStyle.Bold); 71 | Object.StyleMargin(0, 0, 0, TITLE_MARGIN_BOTTOM); 72 | verticalLayout.Add(Object); 73 | 74 | var displayCustomObjectIcon = new Toggle("Display Custom Icon"); 75 | displayCustomObjectIcon.value = settings.displayCustomObjectIcon; 76 | displayCustomObjectIcon.RegisterValueChangedCallback((evt) => 77 | { 78 | Undo.RecordObject(settings, "Change Settings"); 79 | 80 | settings.displayCustomObjectIcon = evt.newValue; 81 | settings.OnSettingsChanged(nameof(settings.displayCustomObjectIcon)); 82 | }); 83 | displayCustomObjectIcon.StyleMarginLeft(CONTENT_MARGIN_LEFT); 84 | verticalLayout.Add(displayCustomObjectIcon); 85 | 86 | var View = new Label("View"); 87 | View.StyleFont(FontStyle.Bold); 88 | View.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 89 | verticalLayout.Add(View); 90 | 91 | var displayRowBackground = new Toggle("Display RowBackground"); 92 | displayRowBackground.value = settings.displayRowBackground; 93 | displayRowBackground.RegisterValueChangedCallback((evt) => 94 | { 95 | Undo.RecordObject(settings, "Change Settings"); 96 | 97 | settings.displayRowBackground = evt.newValue; 98 | settings.OnSettingsChanged(nameof(settings.displayRowBackground)); 99 | }); 100 | displayRowBackground.StyleMarginLeft(CONTENT_MARGIN_LEFT); 101 | verticalLayout.Add(displayRowBackground); 102 | 103 | var displayTreeView = new Toggle("Display TreeView"); 104 | displayTreeView.value = settings.displayTreeView; 105 | displayTreeView.RegisterValueChangedCallback((evt) => 106 | { 107 | Undo.RecordObject(settings, "Change Settings"); 108 | 109 | settings.displayTreeView = evt.newValue; 110 | settings.OnSettingsChanged(nameof(settings.displayTreeView)); 111 | }); 112 | displayTreeView.StyleMarginLeft(CONTENT_MARGIN_LEFT); 113 | verticalLayout.Add(displayTreeView); 114 | 115 | var displayGrid = new Toggle("Display Grid"); 116 | displayGrid.value = settings.displayGrid; 117 | displayGrid.RegisterValueChangedCallback((evt) => 118 | { 119 | Undo.RecordObject(settings, "Change Settings"); 120 | 121 | settings.displayGrid = evt.newValue; 122 | settings.OnSettingsChanged(nameof(settings.displayGrid)); 123 | }); 124 | displayGrid.StyleMarginLeft(CONTENT_MARGIN_LEFT); 125 | verticalLayout.Add(displayGrid); 126 | 127 | var Components = new Label("Components"); 128 | Components.StyleFont(FontStyle.Bold); 129 | Components.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 130 | verticalLayout.Add(Components); 131 | 132 | var displayComponents = new Toggle("Display Components Icon"); 133 | displayComponents.value = settings.displayComponents; 134 | displayComponents.RegisterValueChangedCallback((evt) => 135 | { 136 | Undo.RecordObject(settings, "Change Settings"); 137 | 138 | settings.displayComponents = evt.newValue; 139 | settings.OnSettingsChanged(nameof(settings.displayComponents)); 140 | }); 141 | displayComponents.StyleMarginLeft(CONTENT_MARGIN_LEFT); 142 | verticalLayout.Add(displayComponents); 143 | 144 | var componentAlignment = new EnumField(settings.componentAlignment); 145 | componentAlignment.label = "Component Alignment"; 146 | componentAlignment.RegisterValueChangedCallback((evt) => 147 | { 148 | Undo.RecordObject(settings, "Change Settings"); 149 | 150 | settings.componentAlignment = (HierarchySettings.ElementAlignment)evt.newValue; 151 | settings.OnSettingsChanged(nameof(settings.componentAlignment)); 152 | }); 153 | componentAlignment.StyleMarginLeft(CONTENT_MARGIN_LEFT); 154 | verticalLayout.Add(componentAlignment); 155 | 156 | var componentDisplayMode = new EnumField(settings.componentDisplayMode); 157 | componentDisplayMode.label = "Component Display Mode"; 158 | componentDisplayMode.StyleMarginLeft(CONTENT_MARGIN_LEFT); 159 | verticalLayout.Add(componentDisplayMode); 160 | 161 | var componentListInput = new TextField("Components"); 162 | componentListInput.value = string.Join(" ", settings.components); 163 | componentListInput.StyleMarginLeft(CONTENT_MARGIN_LEFT); 164 | verticalLayout.Add(componentListInput); 165 | componentListInput.RegisterValueChangedCallback((evt) => 166 | { 167 | Undo.RecordObject(settings, "Change Settings"); 168 | 169 | settings.components = evt.newValue.Split(' '); 170 | settings.OnSettingsChanged(nameof(settings.components)); 171 | }); 172 | componentDisplayMode.RegisterValueChangedCallback((evt) => 173 | { 174 | Undo.RecordObject(settings, "Change Settings"); 175 | 176 | settings.componentDisplayMode = (HierarchySettings.ComponentDisplayMode)evt.newValue; 177 | switch (settings.componentDisplayMode) 178 | { 179 | case HierarchySettings.ComponentDisplayMode.Specified: 180 | componentListInput.StyleDisplay(true); 181 | break; 182 | 183 | case HierarchySettings.ComponentDisplayMode.Ignore: 184 | componentListInput.StyleDisplay(true); 185 | break; 186 | 187 | case HierarchySettings.ComponentDisplayMode.All: 188 | componentListInput.StyleDisplay(false); 189 | break; 190 | 191 | case HierarchySettings.ComponentDisplayMode.ScriptOnly: 192 | componentListInput.StyleDisplay(false); 193 | break; 194 | } 195 | 196 | settings.OnSettingsChanged(nameof(settings.componentDisplayMode)); 197 | }); 198 | 199 | var componentSizeEnum = HierarchySettings.ComponentSize.Normal; 200 | switch (settings.componentSize) 201 | { 202 | case 12: 203 | componentSizeEnum = HierarchySettings.ComponentSize.Small; 204 | break; 205 | 206 | case 14: 207 | componentSizeEnum = HierarchySettings.ComponentSize.Normal; 208 | break; 209 | 210 | case 16: 211 | componentSizeEnum = HierarchySettings.ComponentSize.Large; 212 | break; 213 | } 214 | 215 | var componentSize = new EnumField(componentSizeEnum); 216 | componentSize.label = "Component Size"; 217 | componentSize.StyleMarginLeft(CONTENT_MARGIN_LEFT); 218 | componentSize.RegisterValueChangedCallback((evt) => 219 | { 220 | Undo.RecordObject(settings, "Change Settings"); 221 | 222 | switch (evt.newValue) 223 | { 224 | case HierarchySettings.ComponentSize.Small: 225 | settings.componentSize = 12; 226 | break; 227 | 228 | case HierarchySettings.ComponentSize.Normal: 229 | settings.componentSize = 14; 230 | break; 231 | 232 | case HierarchySettings.ComponentSize.Large: 233 | settings.componentSize = 16; 234 | break; 235 | } 236 | 237 | settings.OnSettingsChanged(nameof(settings.componentSize)); 238 | }); 239 | verticalLayout.Add(componentSize); 240 | 241 | var componentSpacing = new IntegerField(); 242 | componentSpacing.label = "Component Spacing"; 243 | componentSpacing.value = settings.componentSpacing; 244 | componentSpacing.StyleMarginLeft(CONTENT_MARGIN_LEFT); 245 | componentSpacing.RegisterValueChangedCallback((evt) => 246 | { 247 | Undo.RecordObject(settings, "Change Settings"); 248 | 249 | settings.componentSpacing = evt.newValue; 250 | settings.OnSettingsChanged(nameof(settings.componentSpacing)); 251 | }); 252 | verticalLayout.Add(componentSpacing); 253 | 254 | var tag = new Label("Tag"); 255 | tag.StyleFont(FontStyle.Bold); 256 | tag.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 257 | verticalLayout.Add(tag); 258 | 259 | var displayTag = new Toggle("Display Tag"); 260 | displayTag.value = settings.displayTag; 261 | displayTag.RegisterValueChangedCallback((evt) => 262 | { 263 | Undo.RecordObject(settings, "Change Settings"); 264 | 265 | settings.displayTag = evt.newValue; 266 | settings.OnSettingsChanged(nameof(settings.displayTag)); 267 | }); 268 | displayTag.StyleMarginLeft(CONTENT_MARGIN_LEFT); 269 | verticalLayout.Add(displayTag); 270 | 271 | var applyTagTargetAndChild = new Toggle("Tag Recursive Change"); 272 | applyTagTargetAndChild.value = settings.applyTagTargetAndChild; 273 | applyTagTargetAndChild.RegisterValueChangedCallback((evt) => 274 | { 275 | Undo.RecordObject(settings, "Change Settings"); 276 | 277 | settings.applyTagTargetAndChild = evt.newValue; 278 | settings.OnSettingsChanged(nameof(settings.applyTagTargetAndChild)); 279 | }); 280 | applyTagTargetAndChild.StyleMarginLeft(CONTENT_MARGIN_LEFT); 281 | verticalLayout.Add(applyTagTargetAndChild); 282 | 283 | var tagAlignment = new EnumField(settings.tagAlignment); 284 | tagAlignment.label = "Tag Alignment"; 285 | tagAlignment.RegisterValueChangedCallback((evt) => 286 | { 287 | Undo.RecordObject(settings, "Change Settings"); 288 | 289 | settings.tagAlignment = (HierarchySettings.ElementAlignment)evt.newValue; 290 | settings.OnSettingsChanged(nameof(settings.tagAlignment)); 291 | }); 292 | tagAlignment.StyleMarginLeft(CONTENT_MARGIN_LEFT); 293 | verticalLayout.Add(tagAlignment); 294 | 295 | var layer = new Label("Layer"); 296 | layer.StyleFont(FontStyle.Bold); 297 | layer.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 298 | verticalLayout.Add(layer); 299 | 300 | var displayLayer = new Toggle("Display Layer"); 301 | displayLayer.value = settings.displayLayer; 302 | displayLayer.RegisterValueChangedCallback((evt) => 303 | { 304 | Undo.RecordObject(settings, "Change Settings"); 305 | 306 | settings.displayLayer = evt.newValue; 307 | settings.OnSettingsChanged(nameof(settings.displayLayer)); 308 | }); 309 | displayLayer.style.marginTop = 8; 310 | displayLayer.StyleMarginLeft(CONTENT_MARGIN_LEFT); 311 | verticalLayout.Add(displayLayer); 312 | 313 | var applyLayerTargetAndChild = new Toggle("Layer Recursive Change"); 314 | applyLayerTargetAndChild.value = settings.applyLayerTargetAndChild; 315 | applyLayerTargetAndChild.RegisterValueChangedCallback((evt) => 316 | { 317 | Undo.RecordObject(settings, "Change Settings"); 318 | 319 | settings.applyLayerTargetAndChild = evt.newValue; 320 | settings.OnSettingsChanged(nameof(settings.applyLayerTargetAndChild)); 321 | }); 322 | applyLayerTargetAndChild.StyleMarginLeft(CONTENT_MARGIN_LEFT); 323 | verticalLayout.Add(applyLayerTargetAndChild); 324 | 325 | var layerAlignment = new EnumField(settings.layerAlignment); 326 | layerAlignment.label = "Layer Alignment"; 327 | layerAlignment.RegisterValueChangedCallback((evt) => 328 | { 329 | Undo.RecordObject(settings, "Change Settings"); 330 | 331 | settings.layerAlignment = (HierarchySettings.ElementAlignment)evt.newValue; 332 | settings.OnSettingsChanged(nameof(settings.layerAlignment)); 333 | }); 334 | layerAlignment.StyleMarginLeft(CONTENT_MARGIN_LEFT); 335 | verticalLayout.Add(layerAlignment); 336 | 337 | var advanced = new Label("Advanced"); 338 | advanced.StyleFont(FontStyle.Bold); 339 | advanced.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 340 | verticalLayout.Add(advanced); 341 | 342 | var onlyDisplayWhileMouseHovering = new Toggle("Display Hovering"); 343 | onlyDisplayWhileMouseHovering.tooltip = "Only display while mouse hovering"; 344 | onlyDisplayWhileMouseHovering.StyleMarginTop(7); 345 | onlyDisplayWhileMouseHovering.value = settings.onlyDisplayWhileMouseEnter; 346 | onlyDisplayWhileMouseHovering.RegisterValueChangedCallback((evt) => 347 | { 348 | Undo.RecordObject(settings, "Change Settings"); 349 | 350 | settings.onlyDisplayWhileMouseEnter = evt.newValue; 351 | settings.OnSettingsChanged(nameof(settings.onlyDisplayWhileMouseEnter)); 352 | }); 353 | onlyDisplayWhileMouseHovering.StyleMarginLeft(CONTENT_MARGIN_LEFT); 354 | verticalLayout.Add(onlyDisplayWhileMouseHovering); 355 | 356 | var contentMaskEnumFlags = new EnumFlagsField(settings.contentDisplay); 357 | contentMaskEnumFlags.StyleDisplay(onlyDisplayWhileMouseHovering.value); 358 | contentMaskEnumFlags.label = "Content Mask"; 359 | onlyDisplayWhileMouseHovering.RegisterValueChangedCallback((evt) => { contentMaskEnumFlags.StyleDisplay(evt.newValue); }); 360 | contentMaskEnumFlags.RegisterValueChangedCallback((evt) => 361 | { 362 | Undo.RecordObject(settings, "Change Settings"); 363 | 364 | settings.contentDisplay = (HierarchySettings.ContentDisplay)evt.newValue; 365 | settings.OnSettingsChanged(nameof(settings.contentDisplay)); 366 | }); 367 | contentMaskEnumFlags.style.marginLeft = CONTENT_MARGIN_LEFT; 368 | verticalLayout.Add(contentMaskEnumFlags); 369 | 370 | var Theme = new Label("Theme"); 371 | Theme.StyleFont(FontStyle.Bold); 372 | Theme.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 373 | verticalLayout.Add(Theme); 374 | 375 | if (EditorApplication.isPlayingOrWillChangePlaymode) 376 | { 377 | EditorHelpBox themeWarningPlaymode = 378 | new EditorHelpBox("This setting only available on edit mode.", MessageType.Info); 379 | verticalLayout.Add(themeWarningPlaymode); 380 | } 381 | else 382 | { 383 | EditorHelpBox selectionColorHelpBox = new EditorHelpBox( 384 | "Theme selection color require editor assembly recompile to take affect.\nBy selecting any script, right click -> Reimport. it will force the editor to recompile.", 385 | MessageType.Info); 386 | selectionColorHelpBox.StyleDisplay(false); 387 | verticalLayout.Add(selectionColorHelpBox); 388 | 389 | ColorField colorRowEven = new ColorField("Row Even"); 390 | colorRowEven.value = settings.usedThemeData.colorRowEven; 391 | colorRowEven.StyleMarginLeft(CONTENT_MARGIN_LEFT); 392 | colorRowEven.RegisterValueChangedCallback((evt) => 393 | { 394 | Undo.RecordObject(settings, "Change Settings"); 395 | 396 | if (EditorGUIUtility.isProSkin) 397 | settings.professionalTheme.colorRowEven = evt.newValue; 398 | else 399 | settings.personalTheme.colorRowEven = evt.newValue; 400 | 401 | settings.OnSettingsChanged(); 402 | }); 403 | verticalLayout.Add(colorRowEven); 404 | 405 | ColorField colorRowOdd = new ColorField("Row Odd"); 406 | colorRowOdd.value = settings.usedThemeData.colorRowOdd; 407 | colorRowOdd.StyleMarginLeft(CONTENT_MARGIN_LEFT); 408 | colorRowOdd.RegisterValueChangedCallback((evt) => 409 | { 410 | Undo.RecordObject(settings, "Change Settings"); 411 | 412 | if (EditorGUIUtility.isProSkin) 413 | settings.professionalTheme.colorRowOdd = evt.newValue; 414 | else 415 | settings.personalTheme.colorRowOdd = evt.newValue; 416 | 417 | settings.OnSettingsChanged(); 418 | }); 419 | verticalLayout.Add(colorRowOdd); 420 | 421 | ColorField colorGrid = new ColorField("Grid Color"); 422 | colorGrid.value = settings.usedThemeData.colorGrid; 423 | colorGrid.StyleMarginLeft(CONTENT_MARGIN_LEFT); 424 | colorGrid.RegisterValueChangedCallback((evt) => 425 | { 426 | Undo.RecordObject(settings, "Change Settings"); 427 | 428 | if (EditorGUIUtility.isProSkin) 429 | settings.professionalTheme.colorGrid = evt.newValue; 430 | else 431 | settings.personalTheme.colorGrid = evt.newValue; 432 | 433 | settings.OnSettingsChanged(); 434 | }); 435 | verticalLayout.Add(colorGrid); 436 | 437 | ColorField colorTreeView = new ColorField("TreeView"); 438 | colorTreeView.value = settings.usedThemeData.colorTreeView; 439 | colorTreeView.StyleMarginLeft(CONTENT_MARGIN_LEFT); 440 | colorTreeView.RegisterValueChangedCallback((evt) => 441 | { 442 | Undo.RecordObject(settings, "Change Settings"); 443 | 444 | if (EditorGUIUtility.isProSkin) 445 | settings.professionalTheme.colorTreeView = evt.newValue; 446 | else 447 | settings.personalTheme.colorTreeView = evt.newValue; 448 | 449 | settings.OnSettingsChanged(); 450 | }); 451 | verticalLayout.Add(colorTreeView); 452 | 453 | ColorField colorLockIcon = new ColorField("Lock Icon"); 454 | colorLockIcon.value = settings.usedThemeData.colorLockIcon; 455 | colorLockIcon.StyleMarginLeft(CONTENT_MARGIN_LEFT); 456 | colorLockIcon.RegisterValueChangedCallback((evt) => 457 | { 458 | Undo.RecordObject(settings, "Change Settings"); 459 | 460 | if (EditorGUIUtility.isProSkin) 461 | settings.professionalTheme.colorLockIcon = evt.newValue; 462 | else 463 | settings.personalTheme.colorLockIcon = evt.newValue; 464 | 465 | settings.OnSettingsChanged(); 466 | }); 467 | verticalLayout.Add(colorLockIcon); 468 | 469 | ColorField tagColor = new ColorField("Tag Text"); 470 | tagColor.value = settings.usedThemeData.tagColor; 471 | tagColor.StyleMarginLeft(CONTENT_MARGIN_LEFT); 472 | tagColor.RegisterValueChangedCallback((evt) => 473 | { 474 | Undo.RecordObject(settings, "Change Settings"); 475 | 476 | if (EditorGUIUtility.isProSkin) 477 | settings.professionalTheme.tagColor = evt.newValue; 478 | else 479 | settings.personalTheme.tagColor = evt.newValue; 480 | 481 | settings.OnSettingsChanged(); 482 | }); 483 | verticalLayout.Add(tagColor); 484 | 485 | ColorField layerColor = new ColorField("Layer Text"); 486 | layerColor.value = settings.usedThemeData.layerColor; 487 | layerColor.StyleMarginLeft(CONTENT_MARGIN_LEFT); 488 | layerColor.RegisterValueChangedCallback((evt) => 489 | { 490 | Undo.RecordObject(settings, "Change Settings"); 491 | 492 | if (EditorGUIUtility.isProSkin) 493 | settings.professionalTheme.layerColor = evt.newValue; 494 | else 495 | settings.personalTheme.layerColor = evt.newValue; 496 | 497 | settings.OnSettingsChanged(); 498 | }); 499 | verticalLayout.Add(layerColor); 500 | 501 | ColorField comSelBGColor = new ColorField("Component Selection"); 502 | comSelBGColor.value = settings.usedThemeData.comSelBGColor; 503 | comSelBGColor.StyleMarginLeft(CONTENT_MARGIN_LEFT); 504 | comSelBGColor.RegisterValueChangedCallback((evt) => 505 | { 506 | Undo.RecordObject(settings, "Change Settings"); 507 | 508 | if (EditorGUIUtility.isProSkin) 509 | settings.professionalTheme.comSelBGColor = evt.newValue; 510 | else 511 | settings.personalTheme.comSelBGColor = evt.newValue; 512 | 513 | settings.OnSettingsChanged(); 514 | }); 515 | verticalLayout.Add(comSelBGColor); 516 | } 517 | 518 | var headerTags = new Label("Header Tags"); 519 | headerTags.StyleFont(FontStyle.Bold); 520 | headerTags.StyleMargin(0, 0, TITLE_MARGIN_TOP, TITLE_MARGIN_BOTTOM); 521 | verticalLayout.Add(headerTags); 522 | 523 | if (EditorApplication.isPlayingOrWillChangePlaymode) 524 | { 525 | EditorHelpBox themeWarningPlaymode = 526 | new EditorHelpBox("This setting only available on edit mode.", MessageType.Info); 527 | verticalLayout.Add(themeWarningPlaymode); 528 | } 529 | else 530 | { 531 | var headerCount = new IntegerField(); 532 | headerCount.label = "Header Tag Count"; 533 | headerCount.value = settings.tagData.headerCount; 534 | headerCount.StyleMarginLeft(CONTENT_MARGIN_LEFT); 535 | headerCount.RegisterValueChangedCallback((evt) => 536 | { 537 | Undo.RecordObject(settings, "Change Settings"); 538 | 539 | int value = evt.newValue; 540 | 541 | if (evt.newValue > 32) 542 | { 543 | value = 32; 544 | headerCount.value = value; 545 | } 546 | 547 | settings.tagData.headerCount = value; 548 | 549 | settings.OnSettingsChanged(); 550 | 551 | UpdateHeaderTags(settings, value, verticalLayout); 552 | 553 | Debug.Log("Value Changed"); 554 | }); 555 | verticalLayout.Add(headerCount); 556 | 557 | UpdateHeaderTags(settings, headerCount.value, verticalLayout); 558 | } 559 | Undo.undoRedoPerformed -= OnUndoRedoPerformed; 560 | Undo.undoRedoPerformed += OnUndoRedoPerformed; 561 | }, 562 | 563 | deactivateHandler = () => Undo.undoRedoPerformed -= OnUndoRedoPerformed, 564 | 565 | keywords = new HashSet(new[] { "Hierarchy" }) 566 | }; 567 | 568 | provider.Repaint(); 569 | 570 | return provider; 571 | } 572 | 573 | private static void OnUndoRedoPerformed() 574 | { 575 | SettingsService.NotifySettingsProviderChanged(); 576 | 577 | if (instance != null) 578 | { 579 | instance.onSettingsChanged?.Invoke(nameof(instance.components)); // Refresh components on undo & redo 580 | } 581 | } 582 | 583 | static void UpdateHeaderTags(HierarchySettings settings, int count, VerticalLayout layout) 584 | { 585 | int difference = count - settings.tagData.headerTag.Count; 586 | if (difference > 0) 587 | { 588 | ExpandList(settings.tagData.headerTag, count); 589 | ExpandList(settings.tagData.headerColor, count); 590 | } 591 | else if (difference < 0) 592 | { 593 | ReduceList(settings.tagData.headerTag, count); 594 | ReduceList(settings.tagData.headerColor, count); 595 | } 596 | 597 | for (int i = 0; i < settings.tagData.headerTag.Count; i++) 598 | { 599 | int index = i; 600 | 601 | HorizontalLayout horizontalLayout = new HorizontalLayout(); 602 | 603 | TextField tagName = new TextField("Tag Name: " + index); 604 | tagName.value = settings.tagData.headerTag[i]; 605 | tagName.StyleMarginLeft(CONTENT_MARGIN_LEFT); 606 | tagName.StyleWidth(250); 607 | tagName.RegisterValueChangedCallback((evt) => 608 | { 609 | Undo.RecordObject(settings, "Change Settings"); 610 | 611 | settings.tagData.headerTag[index] = evt.newValue; 612 | 613 | settings.OnSettingsChanged(); 614 | }); 615 | horizontalLayout.Add(tagName); 616 | 617 | ColorField tagColor = new ColorField("Tag Color: " + index); 618 | tagColor.value = settings.tagData.headerColor[index]; 619 | tagColor.RegisterValueChangedCallback((evt) => 620 | { 621 | Undo.RecordObject(settings, "Change Settings"); 622 | 623 | settings.tagData.headerColor[index] = evt.newValue; 624 | 625 | settings.OnSettingsChanged(); 626 | }); 627 | horizontalLayout.Add(tagColor); 628 | 629 | 630 | layout.Add(horizontalLayout); 631 | } 632 | } 633 | 634 | public static void ExpandList(List originalList, int newSize) 635 | { 636 | int countToAdd = newSize - originalList.Count; 637 | if (countToAdd > 0) 638 | { 639 | T defaultElement = default(T); // Default value for the list's element type 640 | originalList.AddRange(Enumerable.Repeat(defaultElement, countToAdd)); 641 | } 642 | } 643 | 644 | public static void ReduceList(List originalList, int newSize) 645 | { 646 | if (originalList.Count > newSize) 647 | { 648 | originalList.RemoveRange(newSize, originalList.Count - newSize); 649 | } 650 | } 651 | 652 | static T[] ExpandArray(T[] originalArray, int newSize) 653 | { 654 | T[] newArray = new T[newSize]; 655 | Array.Copy(originalArray, newArray, Mathf.Min(originalArray.Length, newSize)); 656 | return newArray; 657 | } 658 | 659 | static T[] ReduceArray(T[] originalArray, int newSize) 660 | { 661 | T[] newArray = new T[newSize]; 662 | Array.Copy(originalArray, newArray, Mathf.Min(originalArray.Length, newSize)); 663 | return newArray; 664 | } 665 | } 666 | 667 | } 668 | 669 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchySettingsProvider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17401342e8d17534198d6c9dde0a8f67 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | 5 | namespace Quartzified.Tools.Hierarchy 6 | { 7 | sealed class HierarchyWindow 8 | { 9 | public static Dictionary instances = new Dictionary(); 10 | public static List windows = new List(); 11 | 12 | public int instanceID = Int32.MinValue; 13 | public EditorWindow editorWindow; 14 | 15 | public HierarchyWindow(EditorWindow editorWindow) 16 | { 17 | this.editorWindow = editorWindow; 18 | 19 | instanceID = this.editorWindow.GetInstanceID(); 20 | 21 | instances.Add(instanceID, this.editorWindow); 22 | windows.Add(this); 23 | 24 | // Debug.Log(string.Format("HierarchyWindow {0} Instanced.", instanceID)); 25 | } 26 | 27 | 28 | public void Dispose() 29 | { 30 | editorWindow = null; 31 | instances.Remove(instanceID); 32 | windows.Remove(this); 33 | 34 | // Debug.Log(string.Format("HierarchyWindow {0} Disposed.", instanceID)); 35 | } 36 | 37 | public void SetWindowTitle(string value) 38 | { 39 | if (editorWindow == null) 40 | return; 41 | 42 | editorWindow.titleContent.text = value; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/HierarchyWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73914a26fd896ee4babb37866b40390f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37a334904d0fca3488cfded723cce3ef 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/Resources.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace Quartzified.Tools.Hierarchy 5 | { 6 | internal class Resources 7 | { 8 | private static Texture2D pixelWhite; 9 | 10 | public static Texture2D PixelWhite 11 | { 12 | get 13 | { 14 | if (pixelWhite == null) 15 | { 16 | pixelWhite = new Texture2D(1, 1, TextureFormat.RGBA32, false); 17 | pixelWhite.SetPixel(0, 0, Color.white); 18 | pixelWhite.Apply(); 19 | } 20 | 21 | return pixelWhite; 22 | } 23 | } 24 | 25 | private static Texture2D alphaTexture; 26 | 27 | public static Texture2D AlphaTexture 28 | { 29 | get 30 | { 31 | if (alphaTexture == null) 32 | { 33 | alphaTexture = new Texture2D(16, 16, TextureFormat.RGBA32, false); 34 | 35 | for (int x = 0; x < 16; ++x) 36 | { 37 | for (int y = 0; y < 16; ++y) 38 | { 39 | alphaTexture.SetPixel(x, y, Color.clear); 40 | } 41 | } 42 | 43 | alphaTexture.Apply(); 44 | } 45 | 46 | return alphaTexture; 47 | } 48 | } 49 | 50 | private static Texture2D ramp8x8White; 51 | 52 | public static Texture2D Ramp8x8White 53 | { 54 | get 55 | { 56 | if (ramp8x8White == null) 57 | { 58 | ramp8x8White = new byte[] 59 | { 60 | 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 16, 61 | 0, 0, 0, 16, 8, 6, 0, 0, 0, 31, 243, 255, 97, 0, 0, 0, 40, 73, 68, 65, 84, 56, 17, 99, 252, 62 | 15, 4, 12, 12, 63 | 12, 31, 8, 224, 143, 184, 228, 153, 128, 18, 20, 129, 81, 3, 24, 24, 70, 195, 96, 52, 12, 64 | 64, 153, 104, 224, 65 | 211, 1, 0, 153, 171, 18, 45, 165, 62, 165, 211, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 66 | }.PNGImageDecode(); 67 | } 68 | 69 | return ramp8x8White; 70 | } 71 | } 72 | 73 | internal static readonly Texture lockIconOn = EditorGUIUtility.IconContent("LockIcon-On").image; 74 | } 75 | } 76 | 77 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/Resources.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dad95045c53023c4e80b0706e348be85 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/RowItem.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.SceneManagement; 3 | 4 | namespace Quartzified.Tools.Hierarchy 5 | { 6 | internal class RowItem 7 | { 8 | public int ID = int.MinValue; 9 | public Rect rect; 10 | public Rect nameRect; 11 | public int rowIndex = 0; 12 | public GameObject gameObject; 13 | public bool isNull = true; 14 | public bool isPrefab = false; 15 | public bool isPrefabMissing = false; 16 | public bool isRootObject = false; 17 | public bool isSelected = false; 18 | public bool isFirstRow = false; 19 | public bool isFirstElement = false; 20 | public bool isDirty = false; 21 | public bool isMouseHovering = false; 22 | 23 | public string name 24 | { 25 | get { return isNull ? "Null" : gameObject.name; } 26 | } 27 | 28 | public int childCount 29 | { 30 | get { return gameObject.transform.childCount; } 31 | } 32 | 33 | public Scene Scene 34 | { 35 | get { return gameObject.scene; } 36 | } 37 | 38 | public bool isStatic 39 | { 40 | get { return isNull ? false : gameObject.isStatic; } 41 | } 42 | 43 | public RowItem() 44 | { 45 | } 46 | 47 | public void Dispose() 48 | { 49 | ID = int.MinValue; 50 | gameObject = null; 51 | rect = Rect.zero; 52 | nameRect = Rect.zero; 53 | rowIndex = 0; 54 | isNull = true; 55 | isRootObject = false; 56 | isSelected = false; 57 | isFirstRow = false; 58 | isFirstElement = false; 59 | isDirty = false; 60 | isMouseHovering = false; 61 | } 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/RowItem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 574e0e7ad94fe63418ea370fee4ebd8d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/Styles.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Quartzified.Tools.Hierarchy 4 | { 5 | internal static class Styles 6 | { 7 | internal static GUIStyle Tag = new GUIStyle() 8 | { 9 | padding = new RectOffset(3, 4, 0, 0), 10 | alignment = TextAnchor.MiddleCenter, 11 | fontStyle = FontStyle.Italic, 12 | fontSize = 8, 13 | richText = true, 14 | border = new RectOffset(12, 12, 8, 8), 15 | }; 16 | 17 | internal static GUIStyle Layer = new GUIStyle() 18 | { 19 | padding = new RectOffset(3, 4, 0, 0), 20 | alignment = TextAnchor.MiddleCenter, 21 | fontStyle = FontStyle.Italic, 22 | fontSize = 8, 23 | richText = true, 24 | border = new RectOffset(12, 12, 8, 8), 25 | }; 26 | 27 | internal static GUIStyle Header = new GUIStyle(TreeBoldLabel) 28 | { 29 | richText = true, 30 | normal = new GUIStyleState() { textColor = Color.white } 31 | }; 32 | 33 | internal static GUIStyle TreeBoldLabel 34 | { 35 | get { return UnityEditor.IMGUI.Controls.TreeView.DefaultStyles.boldLabel; } 36 | } 37 | 38 | internal static GUIStyle TreeLabel = new GUIStyle(UnityEditor.IMGUI.Controls.TreeView.DefaultStyles.label) 39 | { 40 | richText = true, 41 | normal = new GUIStyleState() { textColor = Color.white } 42 | }; 43 | } 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /Editor/Hierarchy/Internal/Styles.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 25a71a9aa3df9254c86031e013391f01 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickInspect.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fd6e67d82e9c2c4498c9432ebdd32afe 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickInspect/QuickInspect.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEngine.UIElements; 4 | using UnityEditor; 5 | 6 | namespace Quartzified.Tools.Hierarchy 7 | { 8 | public class QuickInspect : EditorWindow 9 | { 10 | public enum FillMode 11 | { 12 | Default, 13 | Add 14 | } 15 | 16 | ScrollView scrollView; 17 | List editors = new List(); 18 | Color objectNameColor = new Color32(58, 121, 187, 255); 19 | List components = new List(); 20 | List folouts = new List(); 21 | 22 | public static QuickInspect OpenEditor() 23 | { 24 | QuickInspect window = GetWindow("Quick Inspect"); 25 | window.titleContent.image = EditorGUIUtility.IconContent("UnityEditor.InspectorWindow").image; 26 | return window; 27 | } 28 | 29 | void OnEnable() 30 | { 31 | if (rootVisualElement.childCount == 0) 32 | { 33 | scrollView = new ScrollView(ScrollViewMode.Vertical); 34 | rootVisualElement.Add(scrollView); 35 | } 36 | } 37 | 38 | void OnDisable() 39 | { 40 | Dispose(); 41 | } 42 | 43 | void Dispose() 44 | { 45 | components.Clear(); 46 | 47 | while (scrollView.childCount > 0) 48 | { 49 | scrollView[0].RemoveFromHierarchy(); 50 | } 51 | 52 | while (editors.Count > 0) 53 | { 54 | DestroyImmediate(editors[0]); 55 | editors.RemoveAt(0); 56 | } 57 | } 58 | 59 | public void Fill(List objects, FillMode fillMode = FillMode.Default) 60 | { 61 | objects = new List(objects); 62 | 63 | if (fillMode == FillMode.Add) 64 | { 65 | components.RemoveAll(item => item == null); 66 | foreach (var component in components) 67 | if (!objects.Contains(component)) 68 | objects.Add(component); 69 | } 70 | 71 | Dispose(); 72 | components = objects; 73 | folouts.Clear(); 74 | 75 | foreach (var component in components) 76 | { 77 | Foldout folout = new Foldout(string.Format("{0}", component.GetType().Name)); 78 | folout.Value = components.Count == 1 ? true : false; 79 | folout.name = folout.Title; 80 | folouts.Add(folout); 81 | 82 | folout.imageElement.image = EditorGUIUtility.ObjectContent(component, component.GetType()).image; 83 | folout.headerElement.RegisterCallback((evt) => 84 | { 85 | if (evt.button == 1) 86 | { 87 | Rect rect = new Rect(folout.headerElement.layout); 88 | rect.position = evt.mousePosition; 89 | HierarchyEditor.DisplayObjectContextMenu(rect, component, 0); 90 | evt.StopPropagation(); 91 | } 92 | }); 93 | 94 | 95 | Label objectName = new Label(string.Format(" [{0}]", component.name)); 96 | objectName.StyleTextColor(objectNameColor); 97 | objectName.RegisterCallback((evt) => 98 | { 99 | if (evt.button == 0) 100 | { 101 | EditorGUIUtility.PingObject(component); 102 | Selection.activeObject = component; 103 | evt.StopPropagation(); 104 | } 105 | }); 106 | folout.headerElement.Add(objectName); 107 | 108 | Image remove = new Image(); 109 | remove.image = EditorGUIUtility.IconContent("winbtn_win_close").image; 110 | remove.StyleSize(13, 13); 111 | remove.StylePosition(Position.Absolute); 112 | remove.StyleRight(8); 113 | remove.StyleAlignSelf(Align.Center); 114 | remove.RegisterCallback((evt) => 115 | { 116 | if (evt.button == 0) 117 | { 118 | if (component != null) 119 | components.Remove(component); 120 | else 121 | components.RemoveAll(item => item == null); 122 | 123 | Fill(new List(components)); 124 | evt.StopPropagation(); 125 | } 126 | }); 127 | folout.headerElement.Add(remove); 128 | 129 | bool isMat = component is Material; 130 | 131 | Editor editor = null; 132 | 133 | if (isMat) 134 | editor = MaterialEditor.CreateEditor(component) as MaterialEditor; 135 | else 136 | editor = Editor.CreateEditor(component); 137 | 138 | VisualElement inspector = editor.CreateInspectorGUI(); 139 | 140 | if (inspector == null) 141 | { 142 | inspector = new IMGUIContainer(() => 143 | { 144 | bool tempState = EditorGUIUtility.wideMode; 145 | float tempWidth = EditorGUIUtility.labelWidth; 146 | 147 | EditorGUIUtility.wideMode = true; 148 | 149 | if (component is Transform) 150 | EditorGUIUtility.labelWidth = 64; 151 | 152 | if (editor.target != null) 153 | { 154 | if (isMat) 155 | { 156 | MaterialEditor maEditor = editor as MaterialEditor; 157 | 158 | EditorGUILayout.BeginVertical(); 159 | if (maEditor.PropertiesGUI()) 160 | maEditor.PropertiesChanged(); 161 | EditorGUILayout.EndVertical(); 162 | } 163 | else 164 | { 165 | editor.OnInspectorGUI(); 166 | } 167 | 168 | objectName.StyleTextColor(objectNameColor); 169 | } 170 | else 171 | { 172 | objectName.StyleTextColor(Color.red); 173 | EditorGUILayout.HelpBox("Reference not found.", MessageType.Info); 174 | } 175 | 176 | EditorGUIUtility.wideMode = tempState; 177 | EditorGUIUtility.labelWidth = tempWidth; 178 | }); 179 | } 180 | 181 | inspector.style.marginLeft = 16; 182 | inspector.style.marginRight = 2; 183 | inspector.style.marginTop = 4; 184 | 185 | folout.Add(inspector); 186 | editors.Add(editor); 187 | scrollView.Add(folout); 188 | 189 | if (isMat) 190 | { 191 | var preview = new IMGUIContainer(() => 192 | { 193 | editor.DrawPreview(new Rect(0, 0, inspector.layout.size.x, 194 | Mathf.Clamp(inspector.layout.width / 2, 64, 200))); 195 | }); 196 | preview.StyleMarginTop(4); 197 | preview.StretchToParentWidth(); 198 | inspector.RegisterCallback((callback) => { preview.StyleHeight(Mathf.Clamp(inspector.layout.width / 2, 64, 200)); }); 199 | preview.StylePosition(Position.Relative); 200 | preview.name = "Material Preview"; 201 | folout.Add(preview); 202 | } 203 | } 204 | 205 | Repaint(); 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickInspect/QuickInspect.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4491b327f03d38443b1b5c3f6fad3329 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickRename.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 889737827405f034996d3d398e4d587e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickRename/SceneRenamePopup.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.SceneManagement; 3 | using UnityEngine.UIElements; 4 | using UnityEditor; 5 | 6 | namespace Quartzified.Tools.Hierarchy 7 | { 8 | public class SceneRenamePopup : EditorWindow 9 | { 10 | static EditorWindow window; 11 | public Scene scene; 12 | 13 | Label labelField; 14 | TextField nameField; 15 | 16 | public static SceneRenamePopup ShowPopup(Scene scene) 17 | { 18 | if (window == null) 19 | window = ScriptableObject.CreateInstance(); 20 | 21 | Vector2 v2 = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); 22 | window.position = new Rect(v2.x, v2.y, 200, 68); 23 | window.ShowPopup(); 24 | window.Focus(); 25 | 26 | SceneRenamePopup sceneRenamePopup = window as SceneRenamePopup; 27 | sceneRenamePopup.scene = scene; 28 | sceneRenamePopup.nameField.value = scene.name; 29 | sceneRenamePopup.nameField.Query("unity-text-input").First().Focus(); 30 | 31 | return sceneRenamePopup; 32 | } 33 | 34 | public void OnLostFocus() => Close(); 35 | 36 | void OnEnable() 37 | { 38 | rootVisualElement.StyleBorderWidth(1); 39 | Color c = new Color32(58, 121, 187, 255); 40 | rootVisualElement.StyleBorderColor(c); 41 | rootVisualElement.StyleJustifyContent(Justify.Center); 42 | 43 | labelField = new Label(); 44 | labelField.text = "Quick Rename"; 45 | labelField.StylePaddingTop(4); 46 | labelField.StylePaddingLeft(4); 47 | labelField.StylePaddingBottom(4); 48 | rootVisualElement.Add(labelField); 49 | 50 | nameField = new TextField(); 51 | nameField.RegisterCallback((evt) => 52 | { 53 | if (evt.keyCode == KeyCode.Return) Apply(); 54 | }); 55 | rootVisualElement.Add(nameField); 56 | 57 | Button apply = new Button(() => { Apply(); }); 58 | 59 | apply.text = "Apply"; 60 | rootVisualElement.Add(apply); 61 | } 62 | 63 | void Apply() 64 | { 65 | AssetDatabase.RenameAsset(scene.path, nameField.value); 66 | rootVisualElement.StyleDisplay(DisplayStyle.None); 67 | nameField.value = ""; 68 | Close(); 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickRename/SceneRenamePopup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a142028896e06434b8d63f0c31948dec 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickRename/SelectionsRenamePopup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine.UIElements; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Quartzified.Tools.Hierarchy 9 | { 10 | public sealed class SelectionsRenamePopup : EditorWindow 11 | { 12 | static EditorWindow window; 13 | Label labelField; 14 | TextField textField; 15 | EnumField enumModeField; 16 | EditorHelpBox helpBox; 17 | 18 | enum Mode 19 | { 20 | None, 21 | Number, 22 | NumberReverse 23 | } 24 | 25 | 26 | new public static SelectionsRenamePopup ShowPopup() 27 | { 28 | if (window == null) 29 | window = ScriptableObject.CreateInstance(); 30 | 31 | Vector2 v2 = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); 32 | window.position = new Rect(v2.x, v2.y, 200, 92); 33 | window.ShowPopup(); 34 | window.Focus(); 35 | 36 | SelectionsRenamePopup selectionsRenamePopup = window as SelectionsRenamePopup; 37 | selectionsRenamePopup.textField.Query("unity-text-input").First().Focus(); 38 | 39 | return selectionsRenamePopup; 40 | } 41 | 42 | public void OnLostFocus() => Close(); 43 | 44 | void OnEnable() 45 | { 46 | rootVisualElement.StyleBorderWidth(1); 47 | Color c = new Color32(58, 121, 187, 255); 48 | rootVisualElement.StyleBorderColor(c); 49 | rootVisualElement.StyleJustifyContent(Justify.Center); 50 | 51 | labelField = new Label(); 52 | labelField.text = "Quick Rename"; 53 | labelField.StylePaddingTop(4); 54 | labelField.StylePaddingLeft(4); 55 | labelField.StylePaddingBottom(4); 56 | rootVisualElement.Add(labelField); 57 | 58 | textField = new TextField(); 59 | textField.value = "New Name..."; 60 | rootVisualElement.Add(textField); 61 | textField.RegisterCallback((evt) => 62 | { 63 | if (evt.keyCode == KeyCode.Return) Apply(); 64 | }); 65 | 66 | enumModeField = new EnumField(new Mode()); 67 | enumModeField.label = "Mode"; 68 | enumModeField.tooltip = "Rename with prefix."; 69 | enumModeField.labelElement.StyleMinWidth(64); 70 | enumModeField.labelElement.StyleMaxWidth(64); 71 | 72 | rootVisualElement.Add(enumModeField); 73 | 74 | helpBox = new EditorHelpBox("This mode require selections with the same parent.", MessageType.Info); 75 | helpBox.StyleDisplay(false); 76 | rootVisualElement.Add(helpBox); 77 | 78 | enumModeField.RegisterValueChangedCallback((evt) => { OnModeChanged(evt.newValue); }); 79 | 80 | Button apply = new Button(Apply); 81 | apply.text = nameof(Apply); 82 | rootVisualElement.Add(apply); 83 | } 84 | 85 | void OnModeChanged(Enum mode) 86 | { 87 | Rect rect = window.position; 88 | rect.height = 92; 89 | 90 | if (!System.Enum.Equals(mode, Mode.None)) 91 | { 92 | rect.height = 92; 93 | if (!IsSelectionsSameParent()) 94 | { 95 | helpBox.StyleDisplay(true); 96 | rect.height += 44; 97 | } 98 | else 99 | { 100 | helpBox.StyleDisplay(false); 101 | } 102 | } 103 | else 104 | { 105 | rect.height = 92; 106 | helpBox.StyleDisplay(false); 107 | } 108 | 109 | window.position = rect; 110 | } 111 | 112 | bool IsSelectionsSameParent() 113 | { 114 | var parent = Selection.activeGameObject.transform.parent; 115 | foreach (var gameObject in Selection.gameObjects) 116 | { 117 | if (parent != gameObject.transform.parent) 118 | return false; 119 | } 120 | 121 | return true; 122 | } 123 | 124 | void Apply() 125 | { 126 | bool sameParent = IsSelectionsSameParent(); 127 | 128 | List sortedSelections; 129 | 130 | int index = 0; 131 | 132 | if (System.Enum.Equals(enumModeField.value, Mode.NumberReverse)) 133 | { 134 | sortedSelections = Selection.gameObjects.ToList() 135 | .OrderByDescending(gameObject => gameObject.transform.GetSiblingIndex()).ToList(); 136 | } 137 | else 138 | { 139 | sortedSelections = Selection.gameObjects.ToList() 140 | .OrderBy(gameObject => gameObject.transform.GetSiblingIndex()).ToList(); 141 | } 142 | 143 | foreach (GameObject gameObject in sortedSelections) 144 | { 145 | if (gameObject != null) 146 | { 147 | Undo.RegisterCompleteObjectUndo(gameObject, "Selections Renaming..."); 148 | 149 | if (!System.Enum.Equals(enumModeField.value, Mode.None) && sameParent) 150 | gameObject.name = string.Format("{0} ({1})", textField.value, index++); 151 | else 152 | gameObject.name = textField.value; 153 | } 154 | } 155 | 156 | rootVisualElement.StyleDisplay(DisplayStyle.None); 157 | 158 | Close(); 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /Editor/Hierarchy/QuickRename/SelectionsRenamePopup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9d6dd7e0c736b084dae6f67d6f7f733e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resources.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 69af6b3b1c5f59247bb9c330c0823d71, type: 3} 13 | m_Name: Resources 14 | m_EditorClassIdentifier: 15 | listIcons: 16 | - {fileID: 2800000, guid: 62535b6c7266bf440b9aa800596c7806, type: 3} 17 | - {fileID: 2800000, guid: bf7e68a3f72eea64f831f21ac8405a1c, type: 3} 18 | - {fileID: 2800000, guid: 133b094552954f64aa4f77e744113d9a, type: 3} 19 | -------------------------------------------------------------------------------- /Editor/Resources.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06295d1253ebf5245be30f68aa61bb1e 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Settings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 8b7bbe92ee6f2f74ab6bb3656648fd63, type: 3} 13 | m_Name: Settings 14 | m_EditorClassIdentifier: 15 | personalTheme: 16 | colorRowEven: {r: 0.7607844, g: 0.7607844, b: 0.7607844, a: 1} 17 | colorRowOdd: {r: 0.7830189, g: 0.7830189, b: 0.7830189, a: 1} 18 | colorGrid: {r: 0, g: 0, b: 0, a: 0.16078432} 19 | colorTreeView: {r: 0.47843137, g: 0.47843137, b: 0.47843137, a: 1} 20 | colorLockIcon: {r: 0.31764707, g: 0.31764707, b: 0.31764707, a: 1} 21 | tagColor: {r: 0, g: 0, b: 0, a: 1} 22 | layerColor: {r: 0, g: 0, b: 0, a: 1} 23 | comSelBGColor: {r: 0.9198113, g: 0.9645067, b: 1, a: 1} 24 | selectionColor: {r: 0, g: 0.54901963, b: 1, a: 0.5019608} 25 | colorHeaderTitle: {r: 0.078431375, g: 0.078431375, b: 0.078431375, a: 1} 26 | colorHeaderBackground: {r: 0.9098039, g: 0.9098039, b: 0.9098039, a: 1} 27 | professionalTheme: 28 | colorRowEven: {r: 0.21176471, g: 0.21176471, b: 0.21176471, a: 1} 29 | colorRowOdd: {r: 0.1981132, g: 0.1981132, b: 0.1981132, a: 1} 30 | colorGrid: {r: 0.16981131, g: 0.16981131, b: 0.16981131, a: 1} 31 | colorTreeView: {r: 0.39607847, g: 0.39607847, b: 0.39607847, a: 1} 32 | colorLockIcon: {r: 0.69803923, g: 0.69803923, b: 0.69803923, a: 1} 33 | tagColor: {r: 1, g: 1, b: 1, a: 1} 34 | layerColor: {r: 0.754717, g: 0.754717, b: 0.754717, a: 1} 35 | comSelBGColor: {r: 0, g: 0, b: 0, a: 0.5019608} 36 | selectionColor: {r: 0.17254902, g: 0.3647059, b: 0.5294118, a: 1} 37 | colorHeaderTitle: {r: 1, g: 1, b: 1, a: 1} 38 | colorHeaderBackground: {r: 1, g: 1, b: 1, a: 1} 39 | playmodeTheme: 40 | colorRowEven: {r: 0.16941176, g: 0.16941176, b: 0.16941176, a: 1} 41 | colorRowOdd: {r: 0.15849057, g: 0.15849057, b: 0.15849057, a: 1} 42 | colorGrid: {r: 0.085226074, g: 0.086346544, b: 0.105660394, a: 1} 43 | colorTreeView: {r: 0.6113208, g: 0.49309364, b: 0.49309364, a: 0} 44 | colorLockIcon: {r: 0.5584314, g: 0.5584314, b: 0.5584314, a: 1} 45 | tagColor: {r: 0.8, g: 0.8, b: 0.8, a: 1} 46 | layerColor: {r: 0.6037736, g: 0.6037736, b: 0.6037736, a: 1} 47 | comSelBGColor: {r: 0, g: 0, b: 0, a: 0.5019608} 48 | selectionColor: {r: 0.13803922, g: 0.2917647, b: 0.42352945, a: 1} 49 | colorHeaderTitle: {r: 0.8, g: 0.8, b: 0.8, a: 1} 50 | colorHeaderBackground: {r: 0.8, g: 0.8, b: 0.8, a: 1} 51 | tagData: 52 | headerCount: 5 53 | headerTag: 54 | - Red 55 | - Blue 56 | - Green 57 | - Header 58 | - '%2%' 59 | headerColor: 60 | - {r: 1, g: 0, b: 0, a: 0} 61 | - {r: 0, g: 0.03938794, b: 1, a: 0} 62 | - {r: 0.14090152, g: 0.6320754, b: 0.008944447, a: 0} 63 | - {r: 0, g: 0, b: 0, a: 0} 64 | - {r: 0.4056604, g: 0.024875412, b: 0.35751155, a: 0} 65 | activeHierarchy: 1 66 | displayCustomObjectIcon: 1 67 | displayTreeView: 1 68 | displayRowBackground: 1 69 | displayGrid: 1 70 | displayStaticButton: 1 71 | offSetIconAfterName: 8 72 | displayComponents: 1 73 | componentAlignment: 1 74 | componentDisplayMode: 0 75 | components: 76 | - Transform 77 | - RectTransform 78 | componentLimited: 0 79 | componentSize: 16 80 | componentSpacing: 0 81 | displayTag: 0 82 | tagAlignment: 0 83 | displayLayer: 0 84 | layerAlignment: 0 85 | applyStaticTargetAndChild: 1 86 | applyTagTargetAndChild: 1 87 | applyLayerTargetAndChild: 1 88 | useInstantBackground: 1 89 | instantBackgroundColors: 90 | - active: 0 91 | useStartWith: 0 92 | useTag: 0 93 | useLayer: 0 94 | startWith: 95 | tag: 96 | layer: 97 | serializedVersion: 2 98 | m_Bits: 0 99 | color: {r: 0, g: 0, b: 0, a: 0} 100 | - active: 0 101 | useStartWith: 0 102 | useTag: 0 103 | useLayer: 0 104 | startWith: 105 | tag: 106 | layer: 107 | serializedVersion: 2 108 | m_Bits: 0 109 | color: {r: 0, g: 0, b: 0, a: 0} 110 | onlyDisplayWhileMouseEnter: 0 111 | contentDisplay: 6 112 | -------------------------------------------------------------------------------- /Editor/Settings.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 99cc404c2f8083044818702a42a143e4 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/UI Elements.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca7c2ae86e853264abd9c072b731685e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/UI Elements/EditorHelpBox.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine.UIElements; 3 | 4 | namespace Quartzified.Tools.Hierarchy 5 | { 6 | public class EditorHelpBox : VisualElement 7 | { 8 | public string Label 9 | { 10 | get { return label; } 11 | set { label = value; } 12 | } 13 | 14 | private string label = ""; 15 | 16 | public EditorHelpBox(string text, MessageType messageType, bool wide = true) 17 | { 18 | style.marginLeft = style.marginRight = style.marginTop = style.marginBottom = 4; 19 | Label = text; 20 | 21 | IMGUIContainer iMGUIContainer = new IMGUIContainer(() => { EditorGUILayout.HelpBox(label, messageType, wide); }); 22 | 23 | iMGUIContainer.name = nameof(IMGUIContainer); 24 | Add(iMGUIContainer); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Editor/UI Elements/EditorHelpBox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60afb563a920aa24f8f0ca44c5367b17 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/UI Elements/Foldout.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | using UnityEngine.UIElements; 4 | 5 | namespace Quartzified.Tools.Hierarchy 6 | { 7 | public class Foldout : VisualElement 8 | { 9 | public Image imageElement; 10 | public HorizontalLayout headerElement; 11 | public Label labelElement; 12 | public VerticalLayout contentElement; 13 | 14 | Image foloutImage; 15 | 16 | Texture onIcon = EditorGUIUtility.IconContent("IN foldout on@2x").image; 17 | Texture offIcon = EditorGUIUtility.IconContent("IN foldout@2x").image; 18 | 19 | bool value; 20 | 21 | public bool Value 22 | { 23 | get { return value; } 24 | 25 | set 26 | { 27 | this.value = value; 28 | contentElement.StyleDisplay(this.value); 29 | foloutImage.image = this.value ? onIcon : offIcon; 30 | } 31 | } 32 | 33 | public string Title 34 | { 35 | get { return labelElement.text; } 36 | set { labelElement.text = value; } 37 | } 38 | 39 | public Foldout() => Init(""); 40 | 41 | public Foldout(string title) => Init(title); 42 | 43 | private void Init(string title) 44 | { 45 | this.StyleFont(FontStyle.Normal); 46 | this.StyleMinHeight(20); 47 | this.StyleBorderWidth(0, 0, 1, 0); 48 | Color borderColor = EditorGUIUtility.isProSkin 49 | ? new Color32(35, 35, 35, 255) 50 | : new Color32(153, 153, 153, 255); 51 | this.StyleBorderColor(borderColor); 52 | 53 | headerElement = new HorizontalLayout(); 54 | headerElement.StyleHeight(21); 55 | headerElement.StyleMaxHeight(21); 56 | headerElement.StyleMinHeight(21); 57 | headerElement.StylePadding(4, 0, 0, 0); 58 | headerElement.StyleAlignItem(Align.Center); 59 | Color backgroundColor = EditorGUIUtility.isProSkin 60 | ? new Color32(80, 80, 80, 255) 61 | : new Color32(222, 222, 222, 255); 62 | headerElement.StyleBackgroundColor(backgroundColor); 63 | Color hoverBorderColor = new Color32(58, 121, 187, 255); 64 | headerElement.RegisterCallback((evt) => 65 | { 66 | headerElement.StyleBorderWidth(1); 67 | headerElement.StyleBorderColor(hoverBorderColor); 68 | }); 69 | headerElement.RegisterCallback((evt) => 70 | { 71 | headerElement.StyleBorderWidth(0); 72 | headerElement.StyleBorderColor(Color.clear); 73 | }); 74 | base.Add(headerElement); 75 | 76 | contentElement = new VerticalLayout(); 77 | contentElement.StyleDisplay(value); 78 | base.Add(contentElement); 79 | 80 | labelElement = new Label(); 81 | labelElement.text = title; 82 | headerElement.Add(labelElement); 83 | 84 | imageElement = new Image(); 85 | imageElement.name = nameof(imageElement); 86 | imageElement.StyleMargin(0, 4, 0, 0); 87 | imageElement.StyleSize(16, 16); 88 | headerElement.Add(imageElement); 89 | imageElement.SendToBack(); 90 | imageElement.RegisterCallback((evt) => { imageElement.StyleDisplay(imageElement.image == null ? DisplayStyle.None : DisplayStyle.Flex); }); 91 | 92 | foloutImage = new Image(); 93 | foloutImage.StyleWidth(13); 94 | foloutImage.StyleMargin(0, 2, 0, 0); 95 | foloutImage.scaleMode = ScaleMode.ScaleToFit; 96 | foloutImage.image = value ? onIcon : offIcon; 97 | if (!EditorGUIUtility.isProSkin) 98 | foloutImage.tintColor = Color.grey; 99 | headerElement.Add(foloutImage); 100 | foloutImage.SendToBack(); 101 | 102 | 103 | headerElement.RegisterCallback((evt) => 104 | { 105 | if (evt.button == 0) 106 | { 107 | Value = !Value; 108 | evt.StopPropagation(); 109 | } 110 | }); 111 | } 112 | 113 | new public void Add(VisualElement visualElement) 114 | { 115 | contentElement.Add(visualElement); 116 | } 117 | } 118 | } -------------------------------------------------------------------------------- /Editor/UI Elements/Foldout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ced4e1d19fbf5de4bb1ba96873103bc9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/UI Elements/HorizontalLayout.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.UIElements; 2 | 3 | namespace Quartzified.Tools.Hierarchy 4 | { 5 | public class HorizontalLayout : VisualElement 6 | { 7 | public HorizontalLayout() 8 | { 9 | name = nameof(HorizontalLayout); 10 | this.StyleFlexDirection(FlexDirection.Row); 11 | this.StyleFlexGrow(1); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Editor/UI Elements/HorizontalLayout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 26a1a90fbd4566c4b9e3ef94dacefe28 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/UI Elements/VerticalLayout.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.UIElements; 2 | 3 | namespace Quartzified.Tools.Hierarchy 4 | { 5 | public class VerticalLayout : VisualElement 6 | { 7 | public VerticalLayout() 8 | { 9 | name = nameof(VerticalLayout); 10 | this.StyleFlexDirection(FlexDirection.Column); 11 | this.StyleFlexGrow(1); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Editor/UI Elements/VerticalLayout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a1e55666bc468374a812728d3f02af0a 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Hierarchy.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hierarchy.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "QuartzifiedHierarchy.Runtime" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /Hierarchy.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b17f1efeae860a940881c042d852487a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Quartzi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b8a1ffe0bca66514a9c26f3cdae1ae8d 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quartzified-Hierarchy 2 | 3 | ## Origin 4 | Quartzified Hierarchy is a forked version of [Hierarchy 2](https://github.com/truongnguyentungduy/hierarchy-2). 5 | Many things have been fixed, updated and added :) 6 | 7 | ## Features 8 | ### Component Hierarchy 9 | https://user-images.githubusercontent.com/34374881/159352653-d4248ba4-26f4-419b-aa1b-a36a7f478e5a.mp4 10 | 11 | ### Quick Inspect 12 | https://github.com/Quartzified-Tools/Quartzified-Hierarchy/assets/34374881/55cad5c0-6e27-467a-9d9e-4ef4c6eb22eb 13 | 14 | ### Quick Rename 15 | Just use F2 to rename. Works with Scenes as well! 16 | 17 | https://github.com/Quartzified-Tools/Quartzified-Hierarchy/assets/34374881/149836dc-c1a4-4466-aeb1-38d4540ff646 18 | 19 | ### Hierarchy Settings 20 | https://user-images.githubusercontent.com/34374881/159352719-0682b863-55ce-40f2-b4e0-db97f9a7fd94.mp4 21 | 22 | ## FAQ 23 | **Supported Unity Versions?** 24 | Definitely Unity 2022.3.5f1 25 | 26 | | **How to install?** | Comments | 27 | |-------------|-------------| 28 | | Using [Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html) | Simple but no version control | 29 | | [Clone](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository#cloning-a-repository-to-github-desktop) and install as [local package](https://docs.unity3d.com/Manual/upm-ui-local.html) | Download & freely modify the package| 30 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2125d1c1039bf54db4a1b07b1187f4e 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Third Party Notices.md: -------------------------------------------------------------------------------- 1 | This package contains third-party software components governed by the license(s) indicated below: 2 | 3 | Project Forked from: Hierarchy 2 4 | License Type: MIT 5 | 6 | MIT License 7 | Copyright (c) 2020 Trương Nguyễn Tùng Duy 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. -------------------------------------------------------------------------------- /Third Party Notices.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08c6007e25300544394a040f0c53611b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.quartzified.hierarchy", 3 | "version": "0.1.2", 4 | "displayName": "Quartzified Hierarchy", 5 | "description": "Unity Hierarchy Extension", 6 | "unity": "2020.3", 7 | "unityRelease": "20f1", 8 | "documentationUrl": "", 9 | "changelogUrl": "", 10 | "licensesUrl": "", 11 | "keywords": [ 12 | "Quartzified", 13 | "Utility", 14 | "Editor" 15 | ], 16 | "author": { 17 | "name": "Quartzi", 18 | "email": "virgil@quartzi.io", 19 | "url": "https://www.quartzi.io" 20 | }, 21 | "type": "tool" 22 | } 23 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: add55b1959e8e55409edc04eea6a2769 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------