﻿// A collection of UI functions I've developed over the years to improve customization of editor scripts
// By Mochie#8794

using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace Mochie {
	public static class MGUI {

		public enum BlendMode {Opaque, Cutout, Dithered, A2C, Fade, Transparent}

		public static string parentPath = "Assets/Mochie/Unity/Presets";
		public static string presetPath = "Assets/Mochie/Unity";

		public static List<T> FindAssetsByType<T>() where T : UnityEngine.Object {
			List<T> assets = new List<T>();
			string[] guids = AssetDatabase.FindAssets(string.Format("t:{0}", typeof (T).ToString().Replace("UnityEngine.", "")));
			for(int i = 0; i < guids.Length; i++){
				string assetPath = AssetDatabase.GUIDToAssetPath( guids[i] );
				T asset = AssetDatabase.LoadAssetAtPath<T>( assetPath );
				if(asset != null){
					assets.Add(asset);
				}
			}
			return assets;
		}
		
		public static void UpdateMaterials(){
			List<Material> materials = FindAssetsByType<Material>();
			foreach (Material m in materials){
				if (m.shader.name.Contains("Uber Shader")){
					Debug.Log("Selected next material");
					Selection.activeObject = m;
				}
			}
		}
		
		public static void ClearKeywords(Material mat){
			foreach (string s in mat.shaderKeywords){
				mat.DisableKeyword(s);
			}
		}

		public static bool IsXVersion(Material mat){
			return mat.shader.name.Contains(" X") || mat.shader.name.Contains(" X ");
		}

		public static bool IsOutline(Material mat){
			return mat.shader.name.Contains("(Outline)");
		}
		public static void SetBlendMode(Material material, BlendMode blendMode){
			switch (blendMode){
				
				case BlendMode.Opaque:
					material.SetOverrideTag("RenderType", "");
					material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
					material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
					material.SetInt("_ZWrite", 1);
					material.DisableKeyword("_ALPHATEST_ON");
					material.DisableKeyword("_ALPHABLEND_ON");
					material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
					material.renderQueue = -1;
					break;

				case BlendMode.Cutout:
				case BlendMode.Dithered:
				case BlendMode.A2C:
					material.SetOverrideTag("RenderType", "TransparentCutout");
					material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
					material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
					material.SetInt("_ZWrite", 1);
					material.EnableKeyword("_ALPHATEST_ON");
					material.DisableKeyword("_ALPHABLEND_ON");
					material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
					material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
					break;

				case BlendMode.Fade:
					material.SetOverrideTag("RenderType", "Transparent");
					material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
					material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
					material.DisableKeyword("_ALPHATEST_ON");
					material.EnableKeyword("_ALPHABLEND_ON");
					material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
					material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
					break;

				case BlendMode.Transparent:
					material.SetOverrideTag("RenderType", "Transparent");
					material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
					material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
					material.SetInt("_ZWrite", 0);
					material.DisableKeyword("_ALPHATEST_ON");
					material.DisableKeyword("_ALPHABLEND_ON");
					material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
					material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
					break;

				default: break;
			}
		}

		public static void FillArray<T>(T[] array, T value){
			for (int i = 0; i < array.Length; i++)
				array[i] = value;
		}

		public static void FillArray<T>(T[] array, T value, int startIndex, int count){
			for (int i = startIndex; i < startIndex + count; i++)
				array[i] = value;
		}

		public static bool WriteBytes(byte[] bytes, string path){
			try {
				using (var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
				{
					fs.Write(bytes, 0, bytes.Length);
					return true;
				}
			}
			catch (Exception ex) {
				Debug.Log("Exception caught in process: " + ex.ToString());
				return false;
			}
		}

		public static Texture2D GetTextureAsset(string path){
			return (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/" + path, typeof(Texture2D));
		}

		public static void ExclusiveToggle(MaterialEditor me, MaterialProperty[] toggles){
			for (int i = 0; i < toggles.Length; i++){
				me.ShaderProperty(toggles[i], toggles[i].displayName);
				if (toggles[i].floatValue == 1){
					for (int j = 0; j < toggles.Length; j++){
						if (j != i)
							toggles[j].floatValue = 0;
					}
				}
			}
		}

		public static void FramebufferSection(MaterialEditor me, MaterialProperty[] toggles, MaterialProperty gs){
			DisplayWarning("\nFramebuffer features DO NOT WORK IN UNITY 2018 due to Unity fixing the technique/bug used to create the effects.\n\nThey will still function in versions before 2018, but I would not recommend downgrading.\n");
			for (int i = 0; i < toggles.Length; i++){
				if (i == 0)
					me.ShaderProperty(toggles[i], toggles[i].displayName);
				else 
					ToggleSlider(me, "Ghosting", toggles[1], gs);
				if (toggles[i].floatValue == 1){
					for (int j = 0; j < toggles.Length; j++){
						if (j != i)
							toggles[j].floatValue = 0;
					}
				}
			}

		}

		public static void DisplayError(string message){
			EditorGUILayout.HelpBox(message, MessageType.Error);
		}

		public static void DisplayWarning(string message){
			EditorGUILayout.HelpBox(message, MessageType.Warning);
		}

		public static void DisplayInfo(string message){
			EditorGUILayout.HelpBox(message, MessageType.Info);
		}
		
		public static void DisplayText(string message){
			EditorGUILayout.HelpBox(message, MessageType.None);
		}

		public static void MaskProperty(Material mat, MaterialEditor me, bool display, MaterialProperty mask, MaterialProperty scroll){
			if (display){
				me.TexturePropertySingleLine(new GUIContent("Mask Texture"), mask);
				TextureSOScroll(me, mask, scroll, mask.textureValue);
				MGUI.Space4();
			}
		}

		public static bool LinkButton(Texture2D tex, float width, float height, float xPos){
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = width;
			buttonRect.height = height;
			buttonRect.x += ((GetInspectorWidth()/2f)-width/2f)-xPos;
			return GUI.Button(buttonRect, tex);
		}

		public static bool LinkButton(GUIContent g, float width, float height, float xPos){
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = width;
			buttonRect.height = height;
			buttonRect.x += ((GetInspectorWidth()/2f)-width/2f)-xPos;
			return GUI.Button(buttonRect, g);
		}

		public static void DummyProperty(string label, string property){
			Rect r = EditorGUILayout.GetControlRect();
			GUI.Label(r, label);
			r.x += EditorGUIUtility.labelWidth;
			GUI.Label(r, property);
		}

		public static bool SimpleButton(string text, float width, float xPos){
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = width;
			buttonRect.x += xPos;
			return GUI.Button(buttonRect, text);
		}

		public static bool SimpleButton(Texture2D tex, float width, float xPos){
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = width;
			buttonRect.x += xPos;
			return GUI.Button(buttonRect, tex);
		}

		public static bool ResetButton(){
			return SimpleButton("Reset", GetPropertyWidth(), EditorGUIUtility.labelWidth);
		}

		public static void DoResetButton(MaterialProperty vec0, MaterialProperty vec1, Vector4 default0, Vector4 default1){
			if (ResetButton()){
				vec0.vectorValue = default0;
				vec1.vectorValue = default1;
			}
		}

		public static void DoResetButton(MaterialProperty vec0, MaterialProperty vec1){
			if (ResetButton()){
				vec0.vectorValue = new Vector4(0,0,0,0);
				vec1.vectorValue = new Vector4(0,0,0,0);
			}
		}

		public static bool TabButton(Texture2D tex, float offset){
			GUILayout.Space(-28);
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = 27;
			buttonRect.height = 23;
			buttonRect.x += GetInspectorWidth()-offset;
			return GUI.Button(buttonRect, tex);
		}

		public static bool TabButton(GUIContent label, float offset){
			GUILayout.Space(-28);
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = 27;
			buttonRect.height = 23;
			buttonRect.x += GetInspectorWidth()-offset;
			return GUI.Button(buttonRect, label);
		}

		public static bool MedTabButton(Texture2D tex, float offset){
			GUILayout.Space(-25);
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = 23;
			buttonRect.height = 19;
			buttonRect.x += GetInspectorWidth()-offset;
			return GUI.Button(buttonRect, tex);
		}

		public static bool MedTabButton(GUIContent label, float offset){
			GUILayout.Space(-25);
			Rect buttonRect = EditorGUILayout.GetControlRect();
			buttonRect.width = 23;
			buttonRect.height = 19;
			buttonRect.x += GetInspectorWidth()-offset;
			return GUI.Button(buttonRect, label);
		}

		// Slider with a toggle
		public static void ToggleSlider(MaterialEditor me, string label, MaterialProperty toggle, MaterialProperty slider){
			float lw = EditorGUIUtility.labelWidth;
			float indent = lw + 25f;
			GUILayoutOption clickArea = GUILayout.MaxWidth(lw+13f);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = toggle.hasMixedValue;
			var tog = EditorGUILayout.Toggle(label, toggle.floatValue==1, clickArea)?1:0;
			if (EditorGUI.EndChangeCheck())
				toggle.floatValue = tog;
			EditorGUI.showMixedValue = false;

			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += indent;
			r.width -= indent;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = slider.hasMixedValue;
			EditorGUI.BeginDisabledGroup(toggle.floatValue == 0);
			var slide = EditorGUI.Slider(r, slider.floatValue, slider.rangeLimits.x, slider.rangeLimits.y);
			EditorGUI.EndDisabledGroup();
			if (EditorGUI.EndChangeCheck())
				slider.floatValue = slide;
			EditorGUI.showMixedValue = false;
		}

		public static void ToggleIntSlider(MaterialEditor me, string label, MaterialProperty toggle, MaterialProperty slider){
			float lw = EditorGUIUtility.labelWidth;
			float indent = lw + 25f;
			GUILayoutOption clickArea = GUILayout.MaxWidth(lw+13f);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = toggle.hasMixedValue;
			var tog = EditorGUILayout.Toggle(label, toggle.floatValue==1, clickArea)?1:0;
			if (EditorGUI.EndChangeCheck())
				toggle.floatValue = tog;
			EditorGUI.showMixedValue = false;

			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += indent;
			r.width -= indent;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = slider.hasMixedValue;
			EditorGUI.BeginDisabledGroup(toggle.floatValue == 0);
			var slide = (int)EditorGUI.Slider(r, slider.floatValue, slider.rangeLimits.x, slider.rangeLimits.y);
			EditorGUI.EndDisabledGroup();
			if (EditorGUI.EndChangeCheck())
				slider.floatValue = slide;
			EditorGUI.showMixedValue = false;
		}

		// Float with a toggle
		public static void ToggleFloat(MaterialEditor me, string label, MaterialProperty toggle, MaterialProperty floatProp){
			float lw = EditorGUIUtility.labelWidth;
			float indent = lw + 20f;
			GUILayoutOption clickArea = GUILayout.MaxWidth(lw+13f);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = toggle.hasMixedValue;
			var tog = EditorGUILayout.Toggle(label, toggle.floatValue==1, clickArea)?1:0;
			if (EditorGUI.EndChangeCheck())
				toggle.floatValue = tog;
			EditorGUI.showMixedValue = false;

			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += indent;
			r.width -= indent;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = floatProp.hasMixedValue;
			EditorGUI.BeginDisabledGroup(toggle.floatValue == 0);
			var floatVal = EditorGUI.FloatField(r, floatProp.floatValue);
			EditorGUI.EndDisabledGroup();
			if (EditorGUI.EndChangeCheck())
				floatProp.floatValue = floatVal;
			EditorGUI.showMixedValue = false;
		}

		public static void ToggleVector3(string label, MaterialProperty toggle, MaterialProperty vec){
			SpaceN2();
			Vector4 newVec = vec.vectorValue;
			float labelWidth = EditorGUIUtility.labelWidth;
			float fieldWidth = (GetPropertyWidth()/3)-6f;

			Rect r = EditorGUILayout.GetControlRect();
			r.x += labelWidth+18f;

			GUILayout.Space(-19);
			GUILayoutOption clickArea = GUILayout.MaxWidth(labelWidth+7f);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = toggle.hasMixedValue;
			var tog = EditorGUILayout.Toggle(label, toggle.floatValue==1, clickArea)?1:0;
			if (EditorGUI.EndChangeCheck())
				toggle.floatValue = tog;
			EditorGUI.showMixedValue = false;

			EditorGUIUtility.labelWidth = 13f;
			EditorGUI.BeginDisabledGroup(toggle.floatValue == 0);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;

				// X Field
				r.width = fieldWidth-1f;
				newVec.x = EditorGUI.FloatField(r, "X", newVec.x);
				
				// Y Field
				r.x += fieldWidth+1;
				newVec.y = EditorGUI.FloatField(r, "Y", newVec.y);

				// Z Field
				r.x += fieldWidth;
				newVec.z = EditorGUI.FloatField(r, "Z", newVec.z);

			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = newVec;
			EditorGUI.showMixedValue = false;
			EditorGUIUtility.labelWidth = labelWidth;

			EditorGUI.EndDisabledGroup();
			GUILayout.Space(1);
		}

		public static void ToggleVector3W(string label, int toggle, MaterialProperty vec){
			SpaceN2();
			Vector4 newVec = vec.vectorValue;
			float labelWidth = EditorGUIUtility.labelWidth;
			float fieldWidth = (GetPropertyWidth()/3)-6f;

			Rect r = EditorGUILayout.GetControlRect();
			r.x += labelWidth+18f;

			GUILayout.Space(-19);
			GUILayoutOption clickArea = GUILayout.MaxWidth(labelWidth+14f);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;
			var tog = EditorGUILayout.Toggle(label, toggle == 1, clickArea)?1:0;
			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = new Vector4(vec.vectorValue.x, vec.vectorValue.y, vec.vectorValue.z, tog);
			EditorGUI.showMixedValue = false;

			EditorGUIUtility.labelWidth = 13f;
			EditorGUI.BeginDisabledGroup(toggle == 0);

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;

				// X Field
				r.width = fieldWidth-1f;
				newVec.x = EditorGUI.FloatField(r, "X", newVec.x);
				
				// Y Field
				r.x += fieldWidth+1;
				newVec.y = EditorGUI.FloatField(r, "Y", newVec.y);

				// Z Field
				r.x += fieldWidth;
				newVec.z = EditorGUI.FloatField(r, "Z", newVec.z);

			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = new Vector4(newVec.x, newVec.y, newVec.z, tog);
			EditorGUI.showMixedValue = false;
			EditorGUIUtility.labelWidth = labelWidth;

			EditorGUI.EndDisabledGroup();
			GUILayout.Space(1);
		}

		// Vector3 property with corrected width scaling
		public static void Vector3Field(MaterialProperty vec, string label){
			SpaceN2();
			Vector4 newVec = vec.vectorValue;
			float labelWidth = EditorGUIUtility.labelWidth;
			float fieldWidth = GetPropertyWidth()/3;

			EditorGUILayout.LabelField("        "+ label);
			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += labelWidth;
			EditorGUIUtility.labelWidth = 13f;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;

				// X Field
				r.width = fieldWidth-1f;
				newVec.x = EditorGUI.FloatField(r, "X", newVec.x);
				
				// Y Field
				r.x += fieldWidth+1;
				newVec.y = EditorGUI.FloatField(r, "Y", newVec.y);

				// Z Field
				r.x += fieldWidth;
				newVec.z = EditorGUI.FloatField(r, "Z", newVec.z);

			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = newVec;
			EditorGUI.showMixedValue = false;
			EditorGUIUtility.labelWidth = labelWidth;
		}

		// Vector3 property with corrected width scaling
		public static void Vector3FieldRGB(MaterialProperty vec, string label){
			SpaceN2();
			Vector4 newVec = vec.vectorValue;
			float labelWidth = EditorGUIUtility.labelWidth;
			float fieldWidth = GetPropertyWidth()/3;

			EditorGUILayout.LabelField(label);
			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += labelWidth;
			EditorGUIUtility.labelWidth = 13f;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;

				// X Field
				r.width = fieldWidth-1f;
				newVec.x = EditorGUI.FloatField(r, "R", newVec.x);
				
				// Y Field
				r.x += fieldWidth+1;
				newVec.y = EditorGUI.FloatField(r, "G", newVec.y);

				// Z Field
				r.x += fieldWidth;
				newVec.z = EditorGUI.FloatField(r, "B", newVec.z);

			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = newVec;
			EditorGUI.showMixedValue = false;
			EditorGUIUtility.labelWidth = labelWidth;
		}

		// Vector2 property with corrected width scaling
		public static void Vector2Field(MaterialProperty vec, string label){
			SpaceN2();
			Vector4 newVec = vec.vectorValue;
			float labelWidth = EditorGUIUtility.labelWidth;
			float fieldWidth = GetPropertyWidth()/2;

			EditorGUILayout.LabelField(label);
			GUILayout.Space(-18);
			Rect r = EditorGUILayout.GetControlRect();
			r.x += labelWidth;
			EditorGUIUtility.labelWidth = 13f;

			EditorGUI.BeginChangeCheck();
			EditorGUI.showMixedValue = vec.hasMixedValue;

				// X Field
				r.width = fieldWidth-1f;
				newVec.x = EditorGUI.FloatField(r, "X", newVec.x);
				
				// Y Field
				r.x += fieldWidth+1;
				newVec.y = EditorGUI.FloatField(r, "Y", newVec.y);

			if (EditorGUI.EndChangeCheck())
				vec.vectorValue = newVec;
			EditorGUI.showMixedValue = false;
			EditorGUIUtility.labelWidth = labelWidth;
		}

		public static void CenteredTexture(Texture2D tex1, Texture2D tex2, float spacing, float upperMargin, float lowerMargin){
			GUILayout.Space(upperMargin);
			GUILayout.BeginHorizontal();
			GUILayout.FlexibleSpace();
			GUILayout.Label(tex1);
			GUILayout.Space(spacing);
			GUILayout.Label(tex2);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Space(lowerMargin);
		}
		public static void CenteredTexture(Texture2D tex, float upperMargin, float lowerMargin){
			GUILayout.Space(upperMargin);
			GUILayout.BeginHorizontal();
			GUILayout.FlexibleSpace();
			GUILayout.Label(tex);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Space(lowerMargin);
		}

		public static void CenteredText(string text, int fontSize, float upperMargin, float lowerMargin){
			GUIStyle f = new GUIStyle(EditorStyles.boldLabel);
			f.fontSize = fontSize;
			GUILayout.Space(upperMargin);
			GUILayout.BeginHorizontal();
			GUILayout.FlexibleSpace();
			GUILayout.Label(text, f);
			GUILayout.FlexibleSpace();
			GUILayout.EndHorizontal();
			GUILayout.Space(lowerMargin);
		}

		public static void VersionLabel(string text, int fontSize, float upperMargin, float offset){
			GUIStyle f = new GUIStyle(EditorStyles.boldLabel);
			f.fontSize = fontSize;
			float iw = GetInspectorWidth()+offset;
			GUILayout.Space(upperMargin);
			Rect r = EditorGUILayout.GetControlRect();
			r.x = iw/2.0f;
			
			GUI.Label(r, text, f);
		}

		// Label for the third property in TexturePropertySingleLine
		public static void TexPropLabel(string text, int offset){
			GUILayout.Space(-20);
			Rect rm = EditorGUILayout.GetControlRect();
			rm.x += GetInspectorWidth()-offset;
			EditorGUI.LabelField(rm, text);
		}

		public static void PropLabel(string text, int offset){
			GUILayout.Space(-18);
			Rect rm = EditorGUILayout.GetControlRect();
			rm.x += EditorGUIUtility.labelWidth+offset+14.0f;
			EditorGUI.LabelField(rm, text);
		}
		
		// Draws a tinted box behind properties
		public static void ContentBox(int boxSize){
			Rect pos = GUILayoutUtility.GetRect(0f, boxSize);
			pos.width = GetInspectorWidth()+6f;
			pos.x -= 4f;
			Space4();
			GUI.Box(pos, "");
			GUILayout.Space(-boxSize);
		}
		
		// Draws a line across the inspector window
		static public void Divider(){
			Space4();
			Rect pos = EditorGUILayout.GetControlRect();
			pos.width = GetInspectorWidth();
			pos.height = 0.5f;
			pos.x -= 5f;
			GUI.Box(pos, "");
			GUILayout.Space(-8);
		}

		// Need this because the provided parameter doesn't include the width of the scrollbar
		public static float GetInspectorWidth(){
			EditorGUILayout.BeginHorizontal();
			GUILayout.FlexibleSpace();
			EditorGUILayout.EndHorizontal();
			return GUILayoutUtility.GetLastRect().width;
		}

		public static float GetPropertyWidth(){
			float lw = EditorGUIUtility.labelWidth;
			float iw = GetInspectorWidth();
			return iw - lw;
		}

		// Check if the name of the shader contains a specified string
		static bool CheckName(string name, Material mat){
			return mat.shader.name.Contains(name);
		}

		// Shorthand Scale Offset func with fixed spacing
		public static void TextureSO(MaterialEditor me, MaterialProperty prop){
			me.TextureScaleOffsetProperty(prop);
			Space2();
		}

		// Scale offset property with added scrolling x/y
		public static void TextureSOScroll(MaterialEditor me, MaterialProperty tex, MaterialProperty vec){
			me.TextureScaleOffsetProperty(tex);
			SpaceN2();
			Vector2Field(vec, "Scrolling");
		}

		public static void TextureSOScroll(MaterialEditor me, MaterialProperty tex, MaterialProperty vec, bool shouldDisplay){
			if (shouldDisplay){
				me.TextureScaleOffsetProperty(tex);
				SpaceN2();
				Vector2Field(vec, "Scrolling");
			}
		}

		// Shorthand Scale Offset func with fixed spacing
		public static void TextureSO(MaterialEditor me, MaterialProperty prop, bool shouldDisplay){
			if (shouldDisplay){
				me.TextureScaleOffsetProperty(prop);
				Space2();
			}
		}

		// Shorthand for displaying an error window
		public static void ErrorBox(string message){
			EditorUtility.DisplayDialog("Error", message, "Close");
		}

		public static void PropertyGroup(Action action){
			EditorGUILayout.BeginVertical(EditorStyles.helpBox);
			Space2();
			action();
			Space2();
			EditorGUILayout.EndVertical();
			Space2();
		}

		public static void PropertyGroup(bool shouldDisplay, Action action){
			if (shouldDisplay){
				EditorGUILayout.BeginVertical(EditorStyles.helpBox);
				Space2();
				action();
				Space2();
				EditorGUILayout.EndVertical();
				Space2();
			}
		}

		public static void PropertyGroupLayer(Action action){
			Color col = GUI.backgroundColor;
			GUI.backgroundColor = new Color(0.85f,0.85f,0.85f,1);
			EditorGUILayout.BeginVertical(EditorStyles.helpBox);
			Space2();
			action();
			Space2();
			GUI.backgroundColor = col;
			EditorGUILayout.EndVertical();
			SpaceN2();
		}

		// Replace invalid windows characters with underscores
		public static string ReplaceInvalidChars(string filename) {
			string updated = string.Join("_", filename.Split(Path.GetInvalidFileNameChars())); 
			updated = updated.Replace(" ", "_");
			if (updated == "")
				updated = "_";
			return updated;
		}

		// Shorthand disable group stuff
		public static void ToggleGroup(bool isToggled){
			EditorGUI.BeginDisabledGroup(isToggled);
		}
		public static void ToggleGroupEnd(){
			EditorGUI.EndDisabledGroup();
		}

		public static void BoldLabel(string text){
			EditorGUILayout.LabelField(text, EditorStyles.boldLabel);
		}
		
		// Shorthand spacing funcs
		public static void SpaceN16(){ GUILayout.Space(-16); }
		public static void SpaceN14(){ GUILayout.Space(-14); }
		public static void SpaceN12(){ GUILayout.Space(-12); }
		public static void SpaceN10(){ GUILayout.Space(-10); }
		public static void SpaceN8(){ GUILayout.Space(-8); }
		public static void SpaceN6(){ GUILayout.Space(-6); }
		public static void SpaceN4(){ GUILayout.Space(-4); }
		public static void SpaceN2(){ GUILayout.Space(-2); }
		public static void Space2(){ GUILayout.Space(2); }
		public static void Space4(){ GUILayout.Space(4); }
		public static void Space6(){ GUILayout.Space(6); }
		public static void Space8(){ GUILayout.Space(8); }
		public static void Space10(){ GUILayout.Space(10); }
		public static void Space12(){ GUILayout.Space(12); }
		public static void Space14(){ GUILayout.Space(14); }
		public static void Space16(){ GUILayout.Space(16); }

		public static void SetKeyword(Material mat, string keyword, bool state){
			if (state) mat.EnableKeyword(keyword);
			else mat.DisableKeyword(keyword);
		}

		public static void CustomToggleSlider(string label, MaterialProperty toggle, MaterialProperty value, float min, float max){
			float iw = GetInspectorWidth();
			float lw = EditorGUIUtility.labelWidth;
			GUILayoutOption clickArea = GUILayout.MaxWidth(lw+13);
			Rect r0 = EditorGUILayout.GetControlRect();
			Rect r1 = r0;
			GUI.Label(r0, label);
			
			r0.width = iw-lw-(77);
			r0.x += lw+22;
			r1.width = 50;
			r1.x += iw-50;

			GUILayout.Space(-18);
			toggle.floatValue = EditorGUILayout.Toggle(" ", toggle.floatValue==1, clickArea)?1:0;
			EditorGUI.BeginDisabledGroup(toggle.floatValue == 0);
			value.floatValue = GUI.HorizontalSlider(r0, value.floatValue, min, max);
			value.floatValue = EditorGUI.IntField(r1, (int)value.floatValue);
			EditorGUI.EndDisabledGroup();
		}
	}

	// public public void FoldoutDivider(){
	// 	Rect pos = EditorGUILayout.GetControlRect();
	// 	pos.width = GetPropertyWidth();
	// 	pos.height = 0.5f;
	// 	pos.x += EditorGUIUtility.labelWidth;
	// 	GUI.Box(pos, "");
	// }

	// public public void FoldoutDividerToggle(){
	// 	GUILayout.Space(-10);
	// 	Rect pos = EditorGUILayout.GetControlRect();
	// 	pos.width = GetPropertyWidth()-24f;
	// 	pos.height = 0.5f;
	// 	pos.x += EditorGUIUtility.labelWidth+24f;
	// 	GUI.Box(pos, "");
	// 	GUILayout.Space(-8);
	// }
}