├── EditorStyleScriptable ├── Example.meta ├── Scripts.meta ├── Scripts │ ├── Editor.meta │ ├── EditorStyleScriptable.cs.meta │ ├── Editor │ │ ├── EditorStyleEditor.cs.meta │ │ └── EditorStyleEditor.cs │ └── EditorStyleScriptable.cs ├── EditorStyleScriptable │ ├── Example.meta │ ├── Scripts.meta │ ├── Scripts │ │ ├── Editor.meta │ │ ├── Editor │ │ │ ├── EditorStyleEditor.cs.meta │ │ │ └── EditorStyleEditor.cs │ │ ├── EditorStyleScriptable.cs.meta │ │ └── EditorStyleScriptable.cs │ ├── EditorStyles.asset.meta │ └── Example │ │ ├── ExampleGUITest.cs.meta │ │ └── ExampleGUITest.cs ├── EditorStyles.asset.meta └── Example │ ├── ExampleGUITest.cs.meta │ └── ExampleGUITest.cs ├── LICENSE ├── .gitignore └── README.md /EditorStyleScriptable/Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2dc1d7b81aef194c95959d1acce65cc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8ffd2f4ef09900409ba66f9df6603b5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5b5f436a7c25ae4db34e426e4201853 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Example.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d2dc1d7b81aef194c95959d1acce65cc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e8ffd2f4ef09900409ba66f9df6603b5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyles.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0b6bf578bdb8fb48814a6915a5b86c7 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a5b5f436a7c25ae4db34e426e4201853 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/EditorStyles.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0b6bf578bdb8fb48814a6915a5b86c7 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Example/ExampleGUITest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3587830093cd86b4cbabe9679981a69d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts/EditorStyleScriptable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e179756097a0f694d92b0eb818ae69f1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts/Editor/EditorStyleEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c29cbda6bb04fe48adc6ab0834942d0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Example/ExampleGUITest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3587830093cd86b4cbabe9679981a69d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts/Editor/EditorStyleEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4c29cbda6bb04fe48adc6ab0834942d0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts/EditorStyleScriptable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e179756097a0f694d92b0eb818ae69f1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Damian Slocombe 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 | -------------------------------------------------------------------------------- /.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/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Editor Styles Scriptable 3 |

4 |

5 | Small utility addon for Unity to have all EditorStyles cached in a ScriptableObject with previews. Can use the GUIStyles for custom editors, tools or even at game runtime. 6 |

7 | 8 | ## About 9 | 10 | Just while doing some quick debugging, I got really fed up of having to create GUIStyles with tiny changes that were similar to EditorStyles. Now it's super convenient to see the styles and also have them instantly rather than having to create/reference GUIStyles in OnGUI methods. 11 | 12 |

13 | 14 |

15 | 16 | ## Usage 17 | 18 | #### EditorStyleScriptable 19 | The ScriptableObject with all the EditorStyles. Provides some methods for clearing all styles (generally for the editor), adding styles and also finding styles at runtime: 20 | 21 | ```cs 22 | public class ExampleGUITest : MonoBehaviour 23 | { 24 | [SerializeField] 25 | private EditorStyleScriptable editorStyles; 26 | 27 | [SerializeField] 28 | private GUIStyle headerStyle; 29 | 30 | public void Start() 31 | { 32 | //Find the style 33 | headerStyle = editorStyles.GetStyle("BoldLabel"); 34 | } 35 | 36 | public void OnGUI() 37 | { 38 | GUI.Label (new Rect(10, 10, 100, 100), "Time values", headerStyle); 39 | } 40 | } 41 | ``` 42 | 43 | #### EditorStyleEditor 44 | The editor class containing all reflection behaviour to find the styles. Also custom draws and displays the examples in the ScriptableObject. 45 | 46 | #### ExampleGUITest 47 | Example provided showing a slightly more expansive version of the above. 48 | 49 | ## Feedback 50 | 51 | If there are any problems, or requests to expand upon this, feel free to add an issue or pull request! 52 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Example/ExampleGUITest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | #pragma warning disable CS0649 4 | 5 | public class ExampleGUITest : MonoBehaviour 6 | { 7 | [System.Serializable] 8 | private class DebugValues 9 | { 10 | public string name; 11 | public float value; 12 | 13 | public DebugValues(string name) 14 | { 15 | this.name = name; 16 | } 17 | 18 | public void DrawAsGUI(GUIStyle labelStyle, GUIStyle valueStyle) 19 | { 20 | GUILayout.BeginHorizontal (); 21 | { 22 | GUILayout.Label (name, labelStyle); 23 | GUILayout.Label (value.ToString(), valueStyle); 24 | } 25 | GUILayout.EndHorizontal (); 26 | } 27 | } 28 | 29 | [SerializeField] 30 | private EditorStyleScriptable editorStyles; 31 | 32 | [SerializeField] 33 | private GUIStyle headerStyle, labelStyle, valueStyle; 34 | 35 | private DebugValues[] values = new DebugValues[3] 36 | { 37 | new DebugValues("Delta"), 38 | new DebugValues("Frame Count"), 39 | new DebugValues("Time"), 40 | }; 41 | 42 | // Start is called before the first frame update 43 | private void Start() 44 | { 45 | if (editorStyles == null) 46 | { 47 | Debug.LogWarning ("EditorStyles is not assigned!"); 48 | return; 49 | } 50 | 51 | headerStyle = editorStyles.GetStyle ("ObjectFieldThumb"); 52 | headerStyle.alignment = TextAnchor.MiddleCenter; 53 | 54 | labelStyle = editorStyles.GetStyle ("BoldLabel"); 55 | valueStyle = editorStyles.GetStyle ("HelpBox"); 56 | } 57 | 58 | // Update is called once per frame 59 | private void Update() 60 | { 61 | values[0].value = Time.deltaTime; 62 | values[1].value = Time.frameCount; 63 | values[2].value = Time.time; 64 | } 65 | 66 | private void OnGUI() 67 | { 68 | if (editorStyles == null) 69 | return; 70 | 71 | //19 is the height of a field (normally) 72 | //So 19*3 for each of the floats, then another 19 for the header 73 | Rect rect = new Rect (10f, 10f, Screen.width - 20f, 19f * 4f); 74 | 75 | //Draw group of values, can call GUI.skin still too for convenience 76 | GUI.BeginGroup (rect, GUI.skin.box); 77 | { 78 | //Use GUILayout to auto layout 79 | GUILayout.Label ("Time values", headerStyle); 80 | 81 | foreach (var value in values) 82 | value.DrawAsGUI (labelStyle, valueStyle); 83 | } 84 | GUI.EndGroup (); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Example/ExampleGUITest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | #pragma warning disable CS0649 4 | 5 | public class ExampleGUITest : MonoBehaviour 6 | { 7 | [System.Serializable] 8 | private class DebugValues 9 | { 10 | public string name; 11 | public float value; 12 | 13 | public DebugValues(string name) 14 | { 15 | this.name = name; 16 | } 17 | 18 | public void DrawAsGUI(GUIStyle labelStyle, GUIStyle valueStyle) 19 | { 20 | GUILayout.BeginHorizontal (); 21 | { 22 | GUILayout.Label (name, labelStyle); 23 | GUILayout.Label (value.ToString(), valueStyle); 24 | } 25 | GUILayout.EndHorizontal (); 26 | } 27 | } 28 | 29 | [SerializeField] 30 | private EditorStyleScriptable editorStyles; 31 | 32 | [SerializeField] 33 | private GUIStyle headerStyle, labelStyle, valueStyle; 34 | 35 | private DebugValues[] values = new DebugValues[3] 36 | { 37 | new DebugValues("Delta"), 38 | new DebugValues("Frame Count"), 39 | new DebugValues("Time"), 40 | }; 41 | 42 | // Start is called before the first frame update 43 | private void Start() 44 | { 45 | if (editorStyles == null) 46 | { 47 | Debug.LogWarning ("EditorStyles is not assigned!"); 48 | return; 49 | } 50 | 51 | headerStyle = editorStyles.GetStyle ("ObjectFieldThumb"); 52 | headerStyle.alignment = TextAnchor.MiddleCenter; 53 | 54 | labelStyle = editorStyles.GetStyle ("BoldLabel"); 55 | valueStyle = editorStyles.GetStyle ("HelpBox"); 56 | } 57 | 58 | // Update is called once per frame 59 | private void Update() 60 | { 61 | values[0].value = Time.deltaTime; 62 | values[1].value = Time.frameCount; 63 | values[2].value = Time.time; 64 | } 65 | 66 | private void OnGUI() 67 | { 68 | if (editorStyles == null) 69 | return; 70 | 71 | //19 is the height of a field (normally) 72 | //So 19*3 for each of the floats, then another 19 for the header 73 | Rect rect = new Rect (10f, 10f, Screen.width - 20f, 19f * 4f); 74 | 75 | //Draw group of values, can call GUI.skin still too for convenience 76 | GUI.BeginGroup (rect, GUI.skin.box); 77 | { 78 | //Use GUILayout to auto layout 79 | GUILayout.Label ("Time values", headerStyle); 80 | 81 | foreach (var value in values) 82 | value.DrawAsGUI (labelStyle, valueStyle); 83 | } 84 | GUI.EndGroup (); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts/EditorStyleScriptable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | [CreateAssetMenu ()] 6 | public class EditorStyleScriptable : ScriptableObject, ISerializationCallbackReceiver 7 | { 8 | [Serializable] 9 | public class GUIStyleRef 10 | { 11 | public string name; 12 | public GUIStyle style; 13 | 14 | public GUIStyleRef(GUIStyle style) 15 | { 16 | this.name = style.name; 17 | this.style = style; 18 | } 19 | } 20 | 21 | [SerializeField] 22 | private List editorStyles = new List (); 23 | private static Dictionary styleLookup; 24 | 25 | /// 26 | /// Current style count 27 | /// 28 | public int StyleCount => editorStyles.Count; 29 | 30 | /// 31 | /// Add a style to the collection. 32 | /// 33 | public void AddStyle(GUIStyle style) 34 | { 35 | if (styleLookup.ContainsKey (style.name)) 36 | return; 37 | 38 | GUIStyleRef styleRef = new GUIStyleRef (style); 39 | editorStyles.Add (styleRef); 40 | styleLookup.Add (styleRef.name, style); 41 | } 42 | 43 | /// 44 | /// Add multiple styles. Will call for each one. 45 | /// 46 | public void AddStyles(IEnumerable styles) 47 | { 48 | foreach (var style in styles) 49 | AddStyle (style); 50 | } 51 | 52 | /// 53 | /// Clear all style information. 54 | /// 55 | public void ClearStyles() 56 | { 57 | editorStyles.Clear (); 58 | styleLookup?.Clear (); 59 | } 60 | 61 | /// 62 | /// Find a style with the given name. 63 | /// 64 | /// Name of the style to find 65 | public GUIStyle GetStyle(string name) 66 | { 67 | if (string.IsNullOrEmpty (name)) 68 | return null; 69 | 70 | if (styleLookup.ContainsKey (name)) 71 | return styleLookup[name]; 72 | 73 | return null; 74 | } 75 | 76 | public int GetStyleIndex(string name) 77 | { 78 | return editorStyles.FindIndex (s => s.name == name); 79 | } 80 | 81 | /// 82 | /// Return all styles found 83 | /// 84 | public IEnumerable GetStyles() 85 | { 86 | return editorStyles; 87 | } 88 | 89 | #region Serialization 90 | 91 | public void OnBeforeSerialize() 92 | { 93 | if (styleLookup == null) 94 | styleLookup = new Dictionary (); 95 | } 96 | 97 | public void OnAfterDeserialize() 98 | { 99 | if (styleLookup == null) 100 | styleLookup = new Dictionary (); 101 | 102 | //Add the style or update 103 | foreach (var style in editorStyles) 104 | { 105 | if (!styleLookup.ContainsKey (style.name)) 106 | styleLookup.Add (style.name, style.style); 107 | else 108 | styleLookup[style.name] = style.style; 109 | } 110 | } 111 | 112 | #endregion 113 | } -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts/EditorStyleScriptable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | [CreateAssetMenu ()] 6 | public class EditorStyleScriptable : ScriptableObject, ISerializationCallbackReceiver 7 | { 8 | [Serializable] 9 | public class GUIStyleRef 10 | { 11 | public string name; 12 | public GUIStyle style; 13 | 14 | public GUIStyleRef(GUIStyle style) 15 | { 16 | this.name = style.name; 17 | this.style = style; 18 | } 19 | } 20 | 21 | [SerializeField] 22 | private List editorStyles = new List (); 23 | private static Dictionary styleLookup; 24 | 25 | /// 26 | /// Current style count 27 | /// 28 | public int StyleCount => editorStyles.Count; 29 | 30 | /// 31 | /// Add a style to the collection. 32 | /// 33 | public void AddStyle(GUIStyle style) 34 | { 35 | if (styleLookup.ContainsKey (style.name)) 36 | return; 37 | 38 | GUIStyleRef styleRef = new GUIStyleRef (style); 39 | editorStyles.Add (styleRef); 40 | styleLookup.Add (styleRef.name, style); 41 | } 42 | 43 | /// 44 | /// Add multiple styles. Will call for each one. 45 | /// 46 | public void AddStyles(IEnumerable styles) 47 | { 48 | foreach (var style in styles) 49 | AddStyle (style); 50 | } 51 | 52 | /// 53 | /// Clear all style information. 54 | /// 55 | public void ClearStyles() 56 | { 57 | editorStyles.Clear (); 58 | styleLookup?.Clear (); 59 | } 60 | 61 | /// 62 | /// Find a style with the given name. 63 | /// 64 | /// Name of the style to find 65 | public GUIStyle GetStyle(string name) 66 | { 67 | if (string.IsNullOrEmpty (name)) 68 | return null; 69 | 70 | if (styleLookup.ContainsKey (name)) 71 | return styleLookup[name]; 72 | 73 | return null; 74 | } 75 | 76 | public int GetStyleIndex(string name) 77 | { 78 | return editorStyles.FindIndex (s => s.name == name); 79 | } 80 | 81 | /// 82 | /// Return all styles found 83 | /// 84 | public IEnumerable GetStyles() 85 | { 86 | return editorStyles; 87 | } 88 | 89 | #region Serialization 90 | 91 | public void OnBeforeSerialize() 92 | { 93 | if (styleLookup == null) 94 | styleLookup = new Dictionary (); 95 | } 96 | 97 | public void OnAfterDeserialize() 98 | { 99 | if (styleLookup == null) 100 | styleLookup = new Dictionary (); 101 | 102 | //Add the style or update 103 | foreach (var style in editorStyles) 104 | { 105 | if (!styleLookup.ContainsKey (style.name)) 106 | styleLookup.Add (style.name, style.style); 107 | else 108 | styleLookup[style.name] = style.style; 109 | } 110 | } 111 | 112 | #endregion 113 | } -------------------------------------------------------------------------------- /EditorStyleScriptable/Scripts/Editor/EditorStyleEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | 8 | 9 | [CustomEditor (typeof (EditorStyleScriptable))] 10 | public class EditorStyleEditor : Editor 11 | { 12 | private enum ExampleType { BUTTON, LABEL, POPUP, TEXT_FIELD, TOGGLE, SELECTABLE } 13 | private ExampleType exampleType = ExampleType.LABEL; 14 | 15 | // === Reference === 16 | private EditorStyleScriptable cache; 17 | private SerializedProperty styleProperty; 18 | private List serializedStyles; 19 | 20 | // === Display === 21 | private readonly string exampleText = "GUIStyle Example"; 22 | private string styleLookupTest; 23 | private GUIStyle styleLookup; 24 | 25 | // === Reflection === 26 | private EditorStyles stylesClass; 27 | 28 | private Type styleType = typeof (EditorStyles); 29 | private FieldInfo[] styleFields; 30 | 31 | private List foundStyles; 32 | 33 | private readonly BindingFlags methodBindings = BindingFlags.NonPublic | BindingFlags.Instance; 34 | private readonly BindingFlags fieldBindings = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; 35 | 36 | // === Helpers === 37 | private bool HasStyles => cache?.StyleCount > 0; 38 | 39 | private void OnEnable() 40 | { 41 | cache = target as EditorStyleScriptable; 42 | 43 | foundStyles = new List (); 44 | foreach (var style in cache.GetStyles ()) 45 | foundStyles.Add (style.style); 46 | } 47 | 48 | public override void OnInspectorGUI() 49 | { 50 | serializedObject.UpdateIfRequiredOrScript (); 51 | 52 | if (styleProperty == null) 53 | { 54 | styleProperty = serializedObject.FindProperty ("editorStyles"); 55 | CacheSerializedStyles (); 56 | } 57 | 58 | DrawHeaderGUI (); 59 | 60 | if (foundStyles == null || foundStyles.Count == 0) 61 | return; 62 | 63 | DrawContentGUI (); 64 | } 65 | 66 | private void DrawHeaderGUI() 67 | { 68 | styleLookupTest = EditorGUILayout.DelayedTextField ("Style Lookup", styleLookupTest); 69 | styleLookup = cache.GetStyle (styleLookupTest); 70 | 71 | if (styleLookup != null) 72 | { 73 | int index = cache.GetStyleIndex (styleLookupTest); 74 | DrawStyle (styleProperty.GetArrayElementAtIndex (index), foundStyles[index]); 75 | } 76 | else 77 | { 78 | EditorGUILayout.LabelField ("Search for GUIStyle above to display"); 79 | } 80 | 81 | EditorGUILayout.BeginVertical (EditorStyles.helpBox); 82 | { 83 | EditorGUILayout.BeginHorizontal (); 84 | { 85 | if (GUILayout.Button ("Get Styles")) 86 | GetStyles (); 87 | 88 | if (GUILayout.Button ("Clear Styles")) 89 | ClearAll (); 90 | } 91 | EditorGUILayout.EndHorizontal (); 92 | } 93 | EditorGUILayout.EndVertical (); 94 | } 95 | 96 | private void DrawContentGUI() 97 | { 98 | //Display styles and display example GUIStyle 99 | EditorGUILayout.BeginVertical (EditorStyles.helpBox); 100 | { 101 | string info = HasStyles 102 | ? "Editor Styles" 103 | : "No styles found, click the buttonto get all editor styles."; 104 | 105 | EditorGUILayout.BeginHorizontal (); 106 | { 107 | EditorGUILayout.LabelField (info, EditorStyles.boldLabel); 108 | exampleType = (ExampleType)EditorGUILayout.EnumPopup (exampleType); 109 | } 110 | EditorGUILayout.EndHorizontal (); 111 | 112 | EditorGUILayout.Space (); 113 | 114 | EditorGUI.indentLevel++; 115 | { 116 | for (int i = 0; i < serializedStyles.Count; i++) 117 | DrawStyle (serializedStyles[i], foundStyles[i]); 118 | } 119 | EditorGUI.indentLevel--; 120 | } 121 | EditorGUILayout.EndVertical (); 122 | } 123 | 124 | /// 125 | /// Finds all from the EditorStyle class and adds them to the target scriptable. 126 | /// 127 | private void GetStyles() 128 | { 129 | cache.ClearStyles (); 130 | 131 | if (stylesClass == null) 132 | stylesClass = Activator.CreateInstance (); 133 | 134 | //Get method and initialize the styles. This just makes sure the styles are all setup prior 135 | MethodInfo initMethod = styleType.GetMethod ("InitSharedStyles", methodBindings); 136 | initMethod.Invoke (stylesClass, null); 137 | 138 | //Get fields required 139 | styleFields = styleType.GetFields (fieldBindings); 140 | 141 | //Add all styles to list for convenient sorting 142 | foundStyles = new List (); 143 | 144 | foreach (var item in styleFields) 145 | { 146 | object val = item.GetValue (stylesClass); 147 | 148 | if (val is GUIStyle) 149 | foundStyles.Add (val as GUIStyle); 150 | } 151 | 152 | foundStyles.OrderBy (style => style.name); 153 | cache.AddStyles (foundStyles); 154 | 155 | serializedObject.Update (); 156 | 157 | CacheSerializedStyles (); 158 | } 159 | 160 | #region Draw Styles 161 | 162 | private void DrawExample(GUIStyle style) 163 | { 164 | switch (exampleType) 165 | { 166 | case ExampleType.BUTTON: 167 | GUILayout.Button (exampleText, style); 168 | break; 169 | 170 | case ExampleType.LABEL: 171 | EditorGUILayout.LabelField (exampleText, style); 172 | break; 173 | 174 | case ExampleType.POPUP: 175 | EditorGUILayout.Popup (0, new string[] { "One", "Two", "Three" }, style); 176 | 177 | break; 178 | 179 | case ExampleType.TEXT_FIELD: 180 | EditorGUILayout.TextField (exampleText, style); 181 | break; 182 | 183 | case ExampleType.TOGGLE: 184 | EditorGUILayout.ToggleLeft (exampleText, true, style); 185 | break; 186 | 187 | case ExampleType.SELECTABLE: 188 | EditorGUILayout.SelectableLabel (exampleText, style); 189 | 190 | break; 191 | 192 | 193 | } 194 | } 195 | 196 | private void DrawStyle(SerializedProperty property, GUIStyle style) 197 | { 198 | EditorGUILayout.BeginHorizontal (); 199 | { 200 | property.isExpanded = EditorGUILayout.Foldout (property.isExpanded, property.displayName, true); 201 | 202 | GUILayout.FlexibleSpace (); 203 | 204 | DrawExample (style); 205 | } 206 | EditorGUILayout.EndHorizontal (); 207 | 208 | //Do this so the whole window width can be used for the GUIStyle settings 209 | if (property.isExpanded) 210 | { 211 | EditorGUI.indentLevel++; 212 | DrawChildren (property); 213 | EditorGUI.indentLevel--; 214 | } 215 | } 216 | 217 | private void DrawChildren(SerializedProperty parent) 218 | { 219 | bool checkChildren = true; 220 | 221 | SerializedProperty copy = parent.Copy (); 222 | int index = 0; 223 | while (copy.NextVisible (checkChildren)) 224 | { 225 | if (SerializedProperty.EqualContents (copy, parent.GetEndProperty ())) 226 | break; 227 | 228 | EditorGUILayout.PropertyField (copy, true); 229 | 230 | if (!checkChildren) 231 | index++; 232 | 233 | checkChildren = false; 234 | } 235 | } 236 | 237 | #endregion 238 | 239 | #region Helpers 240 | 241 | private void CacheSerializedStyles() 242 | { 243 | serializedStyles = new List (); 244 | 245 | for (int i = 0; i < styleProperty.arraySize; i++) 246 | serializedStyles.Add (styleProperty.GetArrayElementAtIndex (i)); 247 | } 248 | 249 | private void ClearAll() 250 | { 251 | cache.ClearStyles (); 252 | serializedStyles.Clear (); 253 | foundStyles.Clear (); 254 | } 255 | 256 | #endregion 257 | } -------------------------------------------------------------------------------- /EditorStyleScriptable/EditorStyleScriptable/Scripts/Editor/EditorStyleEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using UnityEngine; 6 | using UnityEditor; 7 | 8 | 9 | [CustomEditor (typeof (EditorStyleScriptable))] 10 | public class EditorStyleEditor : Editor 11 | { 12 | private enum ExampleType { BUTTON, LABEL, POPUP, TEXT_FIELD, TOGGLE, SELECTABLE } 13 | private ExampleType exampleType = ExampleType.LABEL; 14 | 15 | // === Reference === 16 | private EditorStyleScriptable cache; 17 | private SerializedProperty styleProperty; 18 | private List serializedStyles; 19 | 20 | // === Display === 21 | private readonly string exampleText = "GUIStyle Example"; 22 | private string styleLookupTest; 23 | private GUIStyle styleLookup; 24 | 25 | // === Reflection === 26 | private EditorStyles stylesClass; 27 | 28 | private Type styleType = typeof (EditorStyles); 29 | private FieldInfo[] styleFields; 30 | 31 | private List foundStyles; 32 | 33 | private readonly BindingFlags methodBindings = BindingFlags.NonPublic | BindingFlags.Instance; 34 | private readonly BindingFlags fieldBindings = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; 35 | 36 | // === Helpers === 37 | private bool HasStyles => cache?.StyleCount > 0; 38 | 39 | private void OnEnable() 40 | { 41 | cache = target as EditorStyleScriptable; 42 | 43 | foundStyles = new List (); 44 | foreach (var style in cache.GetStyles ()) 45 | foundStyles.Add (style.style); 46 | } 47 | 48 | public override void OnInspectorGUI() 49 | { 50 | serializedObject.UpdateIfRequiredOrScript (); 51 | 52 | if (styleProperty == null) 53 | { 54 | styleProperty = serializedObject.FindProperty ("editorStyles"); 55 | CacheSerializedStyles (); 56 | } 57 | 58 | DrawHeaderGUI (); 59 | 60 | if (foundStyles == null || foundStyles.Count == 0) 61 | return; 62 | 63 | DrawContentGUI (); 64 | } 65 | 66 | private void DrawHeaderGUI() 67 | { 68 | styleLookupTest = EditorGUILayout.DelayedTextField ("Style Lookup", styleLookupTest); 69 | styleLookup = cache.GetStyle (styleLookupTest); 70 | 71 | if (styleLookup != null) 72 | { 73 | int index = cache.GetStyleIndex (styleLookupTest); 74 | DrawStyle (styleProperty.GetArrayElementAtIndex (index), foundStyles[index]); 75 | } 76 | else 77 | { 78 | EditorGUILayout.LabelField ("Search for GUIStyle above to display"); 79 | } 80 | 81 | EditorGUILayout.BeginVertical (EditorStyles.helpBox); 82 | { 83 | EditorGUILayout.BeginHorizontal (); 84 | { 85 | if (GUILayout.Button ("Get Styles")) 86 | GetStyles (); 87 | 88 | if (GUILayout.Button ("Clear Styles")) 89 | ClearAll (); 90 | } 91 | EditorGUILayout.EndHorizontal (); 92 | } 93 | EditorGUILayout.EndVertical (); 94 | } 95 | 96 | private void DrawContentGUI() 97 | { 98 | //Display styles and display example GUIStyle 99 | EditorGUILayout.BeginVertical (EditorStyles.helpBox); 100 | { 101 | string info = HasStyles 102 | ? "Editor Styles" 103 | : "No styles found, click the buttonto get all editor styles."; 104 | 105 | EditorGUILayout.BeginHorizontal (); 106 | { 107 | EditorGUILayout.LabelField (info, EditorStyles.boldLabel); 108 | exampleType = (ExampleType)EditorGUILayout.EnumPopup (exampleType); 109 | } 110 | EditorGUILayout.EndHorizontal (); 111 | 112 | EditorGUILayout.Space (); 113 | 114 | EditorGUI.indentLevel++; 115 | { 116 | for (int i = 0; i < serializedStyles.Count; i++) 117 | DrawStyle (serializedStyles[i], foundStyles[i]); 118 | } 119 | EditorGUI.indentLevel--; 120 | } 121 | EditorGUILayout.EndVertical (); 122 | } 123 | 124 | /// 125 | /// Finds all from the EditorStyle class and adds them to the target scriptable. 126 | /// 127 | private void GetStyles() 128 | { 129 | cache.ClearStyles (); 130 | 131 | if (stylesClass == null) 132 | stylesClass = Activator.CreateInstance (); 133 | 134 | //Get method and initialize the styles. This just makes sure the styles are all setup prior 135 | MethodInfo initMethod = styleType.GetMethod ("InitSharedStyles", methodBindings); 136 | initMethod.Invoke (stylesClass, null); 137 | 138 | //Get fields required 139 | styleFields = styleType.GetFields (fieldBindings); 140 | 141 | //Add all styles to list for convenient sorting 142 | foundStyles = new List (); 143 | 144 | foreach (var item in styleFields) 145 | { 146 | object val = item.GetValue (stylesClass); 147 | 148 | if (val is GUIStyle) 149 | foundStyles.Add (val as GUIStyle); 150 | } 151 | 152 | foundStyles.OrderBy (style => style.name); 153 | cache.AddStyles (foundStyles); 154 | 155 | serializedObject.Update (); 156 | 157 | CacheSerializedStyles (); 158 | } 159 | 160 | #region Draw Styles 161 | 162 | private void DrawExample(GUIStyle style) 163 | { 164 | switch (exampleType) 165 | { 166 | case ExampleType.BUTTON: 167 | GUILayout.Button (exampleText, style); 168 | break; 169 | 170 | case ExampleType.LABEL: 171 | EditorGUILayout.LabelField (exampleText, style); 172 | break; 173 | 174 | case ExampleType.POPUP: 175 | EditorGUILayout.Popup (0, new string[] { "One", "Two", "Three" }, style); 176 | 177 | break; 178 | 179 | case ExampleType.TEXT_FIELD: 180 | EditorGUILayout.TextField (exampleText, style); 181 | break; 182 | 183 | case ExampleType.TOGGLE: 184 | EditorGUILayout.ToggleLeft (exampleText, true, style); 185 | break; 186 | 187 | case ExampleType.SELECTABLE: 188 | EditorGUILayout.SelectableLabel (exampleText, style); 189 | 190 | break; 191 | 192 | 193 | } 194 | } 195 | 196 | private void DrawStyle(SerializedProperty property, GUIStyle style) 197 | { 198 | EditorGUILayout.BeginHorizontal (); 199 | { 200 | property.isExpanded = EditorGUILayout.Foldout (property.isExpanded, property.displayName, true); 201 | 202 | GUILayout.FlexibleSpace (); 203 | 204 | DrawExample (style); 205 | } 206 | EditorGUILayout.EndHorizontal (); 207 | 208 | //Do this so the whole window width can be used for the GUIStyle settings 209 | if (property.isExpanded) 210 | { 211 | EditorGUI.indentLevel++; 212 | DrawChildren (property); 213 | EditorGUI.indentLevel--; 214 | } 215 | } 216 | 217 | private void DrawChildren(SerializedProperty parent) 218 | { 219 | bool checkChildren = true; 220 | 221 | SerializedProperty copy = parent.Copy (); 222 | int index = 0; 223 | while (copy.NextVisible (checkChildren)) 224 | { 225 | if (SerializedProperty.EqualContents (copy, parent.GetEndProperty ())) 226 | break; 227 | 228 | EditorGUILayout.PropertyField (copy, true); 229 | 230 | if (!checkChildren) 231 | index++; 232 | 233 | checkChildren = false; 234 | } 235 | } 236 | 237 | #endregion 238 | 239 | #region Helpers 240 | 241 | private void CacheSerializedStyles() 242 | { 243 | serializedStyles = new List (); 244 | 245 | for (int i = 0; i < styleProperty.arraySize; i++) 246 | serializedStyles.Add (styleProperty.GetArrayElementAtIndex (i)); 247 | } 248 | 249 | private void ClearAll() 250 | { 251 | cache.ClearStyles (); 252 | serializedStyles.Clear (); 253 | foundStyles.Clear (); 254 | } 255 | 256 | #endregion 257 | } --------------------------------------------------------------------------------