Files

934 lines
30 KiB
C#

// Copyright (c) Jason Ma
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace LWGUI
{
/// <summary>
/// Misc Function
/// </summary>
public class Helper
{
#region Engine Misc
public static void ObsoleteWarning(string obsoleteStr, string newStr)
{
Debug.LogWarning("'" + obsoleteStr + "' is Obsolete! Please use '" + newStr + "'!");
}
public static bool PropertyValueEquals(MaterialProperty prop1, MaterialProperty prop2)
{
if (prop1.textureValue == prop2.textureValue
&& prop1.vectorValue == prop2.vectorValue
&& prop1.colorValue == prop2.colorValue
&& prop1.floatValue == prop2.floatValue
#if UNITY_2021_1_OR_NEWER
&& prop1.intValue == prop2.intValue
#endif
)
return true;
else
return false;
}
public static bool IsPropertyHideInInspector(MaterialProperty prop)
{
return (prop.flags & MaterialProperty.PropFlags.HideInInspector) != 0;
}
public static string GetKeyWord(string keyWord, string propName)
{
string k;
if (string.IsNullOrEmpty(keyWord) || keyWord == "__")
{
k = propName.ToUpperInvariant() + "_ON";
}
else
{
k = keyWord.ToUpperInvariant();
}
return k;
}
public static void SetShaderKeyWord(Object[] materials, string keyWord, bool isEnable)
{
if (string.IsNullOrEmpty(keyWord) || string.IsNullOrEmpty(keyWord)) return;
foreach (Material m in materials)
{
// delete "_" keywords
if (keyWord == "_")
{
if (m.IsKeywordEnabled(keyWord))
{
m.DisableKeyword(keyWord);
}
continue;
}
if (m.IsKeywordEnabled(keyWord))
{
if (!isEnable) m.DisableKeyword(keyWord);
}
else
{
if (isEnable) m.EnableKeyword(keyWord);
}
}
}
public static void SetShaderKeyWord(Object[] materials, string[] keyWords, int index)
{
Debug.Assert(keyWords.Length >= 1 && index < keyWords.Length && index >= 0,
"KeyWords Length: " + keyWords.Length + " or Index: " + index + " Error! ");
for (int i = 0; i < keyWords.Length; i++)
{
SetShaderKeyWord(materials, keyWords[i], index == i);
}
}
public static void SetShaderPassEnabled(Object[] materials, string[] lightModeNames, bool enabled)
{
if (lightModeNames.Length == 0) return;
foreach (Material material in materials)
{
for (int i = 0; i < lightModeNames.Length; i++)
{
material.SetShaderPassEnabled(lightModeNames[i], enabled);
}
}
}
/// <summary>
/// make Drawer can get all current Material props by customShaderGUI
/// Unity 2019.2+
/// </summary>
public static LWGUI GetLWGUI(MaterialEditor editor)
{
var customShaderGUI = ReflectionHelper.GetCustomShaderGUI(editor);
if (customShaderGUI != null && customShaderGUI is LWGUI)
{
LWGUI gui = customShaderGUI as LWGUI;
return gui;
}
else
{
Debug.LogWarning("Please add \"CustomEditor \"LWGUI.LWGUI\"\" to the end of your shader!");
return null;
}
}
public static void AdaptiveFieldWidth(GUIStyle style, GUIContent content, float extraWidth = 0)
{
var extraTextWidth = Mathf.Max(0, style.CalcSize(content).x + extraWidth - EditorGUIUtility.fieldWidth);
EditorGUIUtility.labelWidth -= extraTextWidth;
EditorGUIUtility.fieldWidth += extraTextWidth;
}
public static void BeginProperty(Rect rect, MaterialProperty property, LWGUI lwgui)
{
#if UNITY_2022_1_OR_NEWER
MaterialEditor.BeginProperty(rect, property);
foreach (var extraPropName in lwgui.perShaderData.propertyDatas[property.name].extraPropNames)
MaterialEditor.BeginProperty(rect, lwgui.perFrameData.propertyDatas[extraPropName].property);
#endif
}
public static void EndProperty(LWGUI lwgui, MaterialProperty property)
{
#if UNITY_2022_1_OR_NEWER
MaterialEditor.EndProperty();
foreach (var extraPropName in lwgui.perShaderData.propertyDatas[property.name].extraPropNames)
MaterialEditor.EndProperty();
#endif
}
public static bool EndChangeCheck(LWGUI lwgui, MaterialProperty property)
{
return lwgui.perFrameData.EndChangeCheck(property.name);
}
#endregion
#region Math
public static float PowPreserveSign(float f, float p)
{
float num = Mathf.Pow(Mathf.Abs(f), p);
if ((double)f < 0.0)
return -num;
return num;
}
#endregion
#region GUI Styles
// Tips: Use properties to fix null reference errors
private static GUIStyle _guiStyles_IconButton;
public static GUIStyle guiStyles_IconButton
{
get
{
if (_guiStyles_IconButton == null)
{
_guiStyles_IconButton = new GUIStyle(
#if UNITY_2021_2_OR_NEWER
EditorStyles.iconButton
#else
"iconButton"
#endif
) { fixedHeight = 0, fixedWidth = 0 };
}
return _guiStyles_IconButton;
}
}
private static GUIStyle _guiStyle_Foldout;
public static GUIStyle guiStyle_Foldout
{
get
{
if (_guiStyle_Foldout == null)
{
_guiStyle_Foldout =
new GUIStyle(EditorStyles.miniButton)
{
contentOffset = new Vector2(22, 0),
fixedHeight = 27,
alignment = TextAnchor.MiddleLeft,
font = EditorStyles.boldLabel.font,
fontSize = EditorStyles.boldLabel.fontSize
#if UNITY_2019_4_OR_NEWER
+ 1,
#endif
};
}
return _guiStyle_Foldout;
}
}
private static GUIStyle _guiStyle_Helpbox;
public static GUIStyle guiStyle_Helpbox
{
get
{
if (_guiStyle_Helpbox == null)
{
_guiStyle_Helpbox = new GUIStyle(EditorStyles.helpBox) { fontSize = 12 };
}
return _guiStyle_Helpbox;
}
}
private static GUIStyle _guiStyles_ToolbarSearchTextFieldPopup;
public static GUIStyle guiStyles_ToolbarSearchTextFieldPopup
{
get
{
if (_guiStyles_ToolbarSearchTextFieldPopup == null)
{
string toolbarSeachTextFieldPopupStr = "ToolbarSeachTextFieldPopup";
{
// ToolbarSeachTextFieldPopup has renamed at Unity 2021.3.28+
#if !UNITY_2022_3_OR_NEWER
string[] versionParts = Application.unityVersion.Split('.');
int majorVersion = int.Parse(versionParts[0]);
int minorVersion = int.Parse(versionParts[1]);
Match patchVersionMatch = Regex.Match(versionParts[2], @"\d+");
int patchVersion = int.Parse(patchVersionMatch.Value);
if (majorVersion >= 2021 && minorVersion >= 3 && patchVersion >= 28)
#endif
{
toolbarSeachTextFieldPopupStr = "ToolbarSearchTextFieldPopup";
}
}
_guiStyles_ToolbarSearchTextFieldPopup = new GUIStyle(toolbarSeachTextFieldPopupStr);
}
return _guiStyles_ToolbarSearchTextFieldPopup;
}
}
#endregion
#region Draw GUI for Drawer
// TODO: use Reflection
// copy and edit of https://github.com/GucioDevs/SimpleMinMaxSlider/blob/master/Assets/SimpleMinMaxSlider/Scripts/Editor/MinMaxSliderDrawer.cs
public static Rect[] SplitRect(Rect rectToSplit, int n)
{
Rect[] rects = new Rect[n];
for (int i = 0; i < n; i++)
{
rects[i] = new Rect(rectToSplit.position.x + (i * rectToSplit.width / n), rectToSplit.position.y,
rectToSplit.width / n, rectToSplit.height);
}
int padding = (int)rects[0].width - 50; // use 50, enough to show 0.xx (2 digits)
int space = 5;
rects[0].width -= padding + space;
rects[2].width -= padding + space;
rects[1].x -= padding;
rects[1].width += padding * 2;
rects[2].x += padding + space;
return rects;
}
public static bool DrawFoldout(Rect rect, ref bool isFolding, bool toggleValue, bool hasToggle, GUIContent label)
{
var toggleRect = new Rect(rect.x + 8f, rect.y + 7f, 13f, 13f);
// Toggle Event
if (hasToggle)
{
if (Event.current.type == EventType.MouseDown && Event.current.button == 0 && toggleRect.Contains(Event.current.mousePosition))
{
toggleValue = !toggleValue;
Event.current.Use();
GUI.changed = true;
}
}
// Button
{
// Cancel Right Click
if (Event.current.type == EventType.MouseDown && Event.current.button == 1 && rect.Contains(Event.current.mousePosition))
Event.current.Use();
var enabled = GUI.enabled;
GUI.enabled = true;
var guiColor = GUI.backgroundColor;
GUI.backgroundColor = isFolding ? Color.white : new Color(0.85f, 0.85f, 0.85f);
if (GUI.Button(rect, label, guiStyle_Foldout))
{
isFolding = !isFolding;
GUI.changed = false;
}
GUI.backgroundColor = guiColor;
GUI.enabled = enabled;
}
// Toggle Icon
if (hasToggle)
{
EditorGUI.Toggle(toggleRect, string.Empty, toggleValue);
}
return toggleValue;
}
#endregion
#region Draw GUI for Material
public static void DrawSplitLine()
{
var rect = EditorGUILayout.GetControlRect(true, 1);
rect.x = 0;
rect.width = EditorGUIUtility.currentViewWidth;
EditorGUI.DrawRect(rect, new Color(0, 0, 0, 0.45f));
}
private static readonly Texture2D _helpboxIcon = EditorGUIUtility.IconContent("console.infoicon").image as Texture2D;
public static void DrawHelpbox(PropertyStaticData propertyStaticData, PropertyDynamicData propertyDynamicData)
{
var helpboxStr = propertyStaticData.helpboxMessages;
if (!string.IsNullOrEmpty(helpboxStr))
{
var content = new GUIContent(helpboxStr, _helpboxIcon);
var helpboxRect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect(true, guiStyle_Helpbox.CalcHeight(content, EditorGUIUtility.currentViewWidth)));
helpboxRect.xMax -= RevertableHelper.revertButtonWidth;
GUI.Label(helpboxRect, content, guiStyle_Helpbox);
// EditorGUI.HelpBox(helpboxRect, helpboxStr, MessageType.Info);
}
}
private static Texture _logo = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("26b9d845eb7b1a747bf04dc84e5bcc2c"));
private static GUIContent _logoGuiContent = new GUIContent(string.Empty, _logo,
"LWGUI (Light Weight Shader GUI)\n\n"
+ "A Lightweight, Flexible, Powerful Unity Shader GUI system.\n\n"
+ "Copyright (c) Jason Ma");
public static void DrawLogo()
{
var logoRect = EditorGUILayout.GetControlRect(false, _logo.height);
var w = logoRect.width;
logoRect.xMin += w * 0.5f - _logo.width * 0.5f;
logoRect.xMax -= w * 0.5f - _logo.width * 0.5f;
if (EditorGUIUtility.currentViewWidth >= logoRect.width && GUI.Button(logoRect, _logoGuiContent, guiStyles_IconButton))
{
Application.OpenURL("https://github.com/JasonMa0012/LWGUI");
}
}
#endregion
#region Toolbar Buttons
private static Material _copiedMaterial;
private static List<string> _copiedProps = new List<string>();
private static Texture _iconCopy = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("9cdef444d18d2ce4abb6bbc4fed4d109"));
private static Texture _iconPaste = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("8e7a78d02e4c3574998524a0842a8ccb"));
private static Texture _iconSelect = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("6f44e40b24300974eb607293e4224ecc"));
private static Texture _iconCheckout = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("72488141525eaa8499e65e52755cb6d0"));
private static Texture _iconExpand = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("2382450e7f4ddb94c9180d6634c41378"));
private static Texture _iconCollapse = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("929b6e5dfacc42b429d715a3e1ca2b57"));
private static Texture _iconVisibility = AssetDatabase.LoadAssetAtPath<Texture>(AssetDatabase.GUIDToAssetPath("9576e23a695b35d49a9fc55c9a948b4f"));
private static GUIContent _guiContentCopy = new GUIContent("", _iconCopy, "Copy Material Properties");
private static GUIContent _guiContentPaste = new GUIContent("", _iconPaste, "Paste Material Properties\n\nRight-click to paste values by type.");
private static GUIContent _guiContentSelect = new GUIContent("", _iconSelect, "Select the Material Asset\n\nUsed to jump from a Runtime Material Instance to a Material Asset.");
private static GUIContent _guiContentChechout = new GUIContent("", _iconCheckout, "Checkout selected Material Assets");
private static GUIContent _guiContentExpand = new GUIContent("", _iconExpand, "Expand All Groups");
private static GUIContent _guiContentCollapse = new GUIContent("", _iconCollapse, "Collapse All Groups");
private static GUIContent _guiContentVisibility = new GUIContent("", _iconVisibility, "Display Mode");
private static string[] _materialInstanceNameEnd = new[] { "_Instantiated", " (Instance)" };
private enum CopyMaterialValueMask
{
Float = 1 << 0,
Vector = 1 << 1,
Texture = 1 << 2,
Keyword = 1 << 3,
RenderQueue = 1 << 4,
Number = Float | Vector,
All = (1 << 5) - 1,
}
private static GUIContent[] _pasteMaterialMenus = new[]
{
new GUIContent("Paste Number Values"),
new GUIContent("Paste Texture Values"),
new GUIContent("Paste Keywords"),
new GUIContent("Paste RenderQueue"),
};
private static uint[] _pasteMaterialMenuValueMasks = new[]
{
(uint)CopyMaterialValueMask.Number,
(uint)CopyMaterialValueMask.Texture,
(uint)CopyMaterialValueMask.Keyword,
(uint)CopyMaterialValueMask.RenderQueue,
};
private static void DoPasteMaterialProperties(LWGUI lwgui , uint valueMask)
{
if (!_copiedMaterial)
{
Debug.LogError("Please copy Material Properties first!");
return;
}
foreach (Material material in lwgui.materialEditor.targets)
{
if (!VersionControlHelper.Checkout(material))
{
Debug.LogError("Material: '" + lwgui.material.name + "' unable to write!");
return;
}
Undo.RecordObject(material, "Paste Material Properties");
for (int i = 0; i < ShaderUtil.GetPropertyCount(_copiedMaterial.shader); i++)
{
var name = ShaderUtil.GetPropertyName(_copiedMaterial.shader, i);
var type = ShaderUtil.GetPropertyType(_copiedMaterial.shader, i);
PastePropertyValueToMaterial(material, name, name, type, valueMask);
}
if ((valueMask & (uint)CopyMaterialValueMask.Keyword) != 0)
material.shaderKeywords = _copiedMaterial.shaderKeywords;
if ((valueMask & (uint)CopyMaterialValueMask.RenderQueue) != 0)
material.renderQueue = _copiedMaterial.renderQueue;
}
}
private static void PastePropertyValueToMaterial(Material material, string srcName, string dstName)
{
for (int i = 0; i < ShaderUtil.GetPropertyCount(_copiedMaterial.shader); i++)
{
var name = ShaderUtil.GetPropertyName(_copiedMaterial.shader, i);
if (name == srcName)
{
var type = ShaderUtil.GetPropertyType(_copiedMaterial.shader, i);
PastePropertyValueToMaterial(material, srcName, dstName, type);
return;
}
}
}
private static void PastePropertyValueToMaterial(Material material, string srcName, string dstName, ShaderUtil.ShaderPropertyType type, uint valueMask = (uint)CopyMaterialValueMask.All)
{
switch (type)
{
case ShaderUtil.ShaderPropertyType.Color:
if ((valueMask & (uint)CopyMaterialValueMask.Vector) != 0)
material.SetColor(dstName, _copiedMaterial.GetColor(srcName));
break;
case ShaderUtil.ShaderPropertyType.Vector:
if ((valueMask & (uint)CopyMaterialValueMask.Vector) != 0)
material.SetVector(dstName, _copiedMaterial.GetVector(srcName));
break;
case ShaderUtil.ShaderPropertyType.TexEnv:
if ((valueMask & (uint)CopyMaterialValueMask.Texture) != 0)
material.SetTexture(dstName, _copiedMaterial.GetTexture(srcName));
break;
// Float
default:
if ((valueMask & (uint)CopyMaterialValueMask.Float) != 0)
material.SetFloat(dstName, _copiedMaterial.GetFloat(srcName));
break;
}
}
public static void DrawToolbarButtons(ref Rect toolBarRect, LWGUI lwgui)
{
// Copy
var buttonRectOffset = toolBarRect.height + 2;
var buttonRect = new Rect(toolBarRect.x, toolBarRect.y, toolBarRect.height, toolBarRect.height);
toolBarRect.xMin += buttonRectOffset;
if (GUI.Button(buttonRect, _guiContentCopy, Helper.guiStyles_IconButton))
{
_copiedMaterial = UnityEngine.Object.Instantiate(lwgui.material);
}
// Paste
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
// Right Click
if (Event.current.type == EventType.MouseDown
&& Event.current.button == 1
&& buttonRect.Contains(Event.current.mousePosition))
{
EditorUtility.DisplayCustomMenu(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 0, 0), _pasteMaterialMenus, -1,
(data, options, selected) =>
{
DoPasteMaterialProperties(lwgui, _pasteMaterialMenuValueMasks[selected]);
}, null);
Event.current.Use();
}
// Left Click
if (GUI.Button(buttonRect, _guiContentPaste, Helper.guiStyles_IconButton))
{
DoPasteMaterialProperties(lwgui, (uint)CopyMaterialValueMask.All);
}
// Select Material Asset, jump from a Runtime Material Instance to a Material Asset
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
if (GUI.Button(buttonRect, _guiContentSelect, Helper.guiStyles_IconButton))
{
if (AssetDatabase.Contains(lwgui.material))
{
Selection.activeObject = lwgui.material;
}
else
{
// Get Material Asset name
var name = lwgui.material.name;
foreach (var nameEnd in _materialInstanceNameEnd)
{
if (name.EndsWith(nameEnd))
{
name = name.Substring(0, name.Length - nameEnd.Length);
break;
}
}
// Get path
var guids = AssetDatabase.FindAssets("t:Material " + name);
var paths = guids.Select(((guid, i) =>
{
var filePath = AssetDatabase.GUIDToAssetPath(guid);
var fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
return (fileName == name && filePath.EndsWith(".mat")) ? filePath : null;
})).Where((s => !string.IsNullOrEmpty(s))).ToArray();
// Select Asset
if (paths.Length == 0)
{
Debug.LogError("Can not find Material Assets with name: " + name);
}
else if (paths.Length > 1)
{
var str = string.Empty;
foreach (string path in paths)
{
str += "\n" + path;
}
Debug.LogWarning("Multiple Material Assets with the same name have been found, select only the first one:" + str);
Selection.activeObject = AssetDatabase.LoadAssetAtPath<Material>(paths[0]);
}
else
{
Selection.activeObject = AssetDatabase.LoadAssetAtPath<Material>(paths[0]);
}
}
}
// Checkout
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
if (GUI.Button(buttonRect, _guiContentChechout, Helper.guiStyles_IconButton))
{
foreach (var material in lwgui.materialEditor.targets)
{
VersionControlHelper.Checkout(material);
}
}
// Expand
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
if (GUI.Button(buttonRect, _guiContentExpand, Helper.guiStyles_IconButton))
{
foreach (var propertyStaticDataPair in lwgui.perShaderData.propertyDatas)
{
if (propertyStaticDataPair.Value.isMain || propertyStaticDataPair.Value.isAdvancedHeader)
propertyStaticDataPair.Value.isExpanding = true;
}
}
// Collapse
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
if (GUI.Button(buttonRect, _guiContentCollapse, Helper.guiStyles_IconButton))
{
foreach (var propertyStaticDataPair in lwgui.perShaderData.propertyDatas)
{
if (propertyStaticDataPair.Value.isMain || propertyStaticDataPair.Value.isAdvancedHeader)
propertyStaticDataPair.Value.isExpanding = false;
}
}
// Display Mode
buttonRect.x += buttonRectOffset;
toolBarRect.xMin += buttonRectOffset;
var color = GUI.color;
if (!lwgui.perShaderData.displayModeData.IsDefaultDisplayMode())
GUI.color = Color.yellow;
if (GUI.Button(buttonRect, _guiContentVisibility, Helper.guiStyles_IconButton))
{
string[] displayModeMenus = new[]
{
"Show All Advanced (" + lwgui.perShaderData.displayModeData.advancedCount + " of " + lwgui.perShaderData.propertyDatas.Count + ")",
"Show All Hidden (" + lwgui.perShaderData.displayModeData.hiddenCount + " of " + lwgui.perShaderData.propertyDatas.Count + ")",
"Show Only Modified (" + lwgui.perFrameData.modifiedCount + " of " + lwgui.perShaderData.propertyDatas.Count + ")",
};
bool[] enabled = new[] { true, true, true };
bool[] separator = new bool[3];
int[] selected = new[]
{
lwgui.perShaderData.displayModeData.showAllAdvancedProperties ? 0 : -1,
lwgui.perShaderData.displayModeData.showAllHiddenProperties ? 1 : -1,
lwgui.perShaderData.displayModeData.showOnlyModifiedProperties ? 2 : -1,
};
ReflectionHelper.DisplayCustomMenuWithSeparators(new Rect(Event.current.mousePosition.x, Event.current.mousePosition.y, 0, 0),
displayModeMenus, enabled, separator, selected,
(data, options, selectedIndex) =>
{
switch (selectedIndex)
{
case 0:
lwgui.perShaderData.displayModeData.showAllAdvancedProperties = !lwgui.perShaderData.displayModeData.showAllAdvancedProperties;
lwgui.perShaderData.ToggleShowAllAdvancedProperties();
break;
case 1:
lwgui.perShaderData.displayModeData.showAllHiddenProperties = !lwgui.perShaderData.displayModeData.showAllHiddenProperties;
break;
case 2:
lwgui.perShaderData.displayModeData.showOnlyModifiedProperties = !lwgui.perShaderData.displayModeData.showOnlyModifiedProperties;
break;
}
});
}
GUI.color = color;
toolBarRect.xMin += 2;
}
#endregion
#region Search Field
private static readonly int s_TextFieldHash = "EditorTextField".GetHashCode();
private static readonly GUIContent[] _searchModeMenus =
(new GUIContent[(int)SearchMode.Num]).Select(((guiContent, i) =>
{
if (i == (int)SearchMode.Num)
return null;
return new GUIContent(((SearchMode)i).ToString());
})).ToArray();
/// <returns>is has changed?</returns>
public static bool DrawSearchField(Rect rect, LWGUI lwgui)
{
bool hasChanged = false;
EditorGUI.BeginChangeCheck();
var revertButtonRect = RevertableHelper.SplitRevertButtonRect(ref rect);
// Get internal TextField ControlID
int controlId = GUIUtility.GetControlID(s_TextFieldHash, FocusType.Keyboard, rect) + 1;
// searching mode
Rect modeRect = new Rect(rect);
modeRect.width = 20f;
if (Event.current.type == UnityEngine.EventType.MouseDown && modeRect.Contains(Event.current.mousePosition))
{
EditorUtility.DisplayCustomMenu(rect, _searchModeMenus, (int)lwgui.perShaderData.searchMode,
(data, options, selected) =>
{
lwgui.perShaderData.searchMode = (SearchMode)selected;
hasChanged = true;
}, null);
Event.current.Use();
}
lwgui.perShaderData.searchString = EditorGUI.TextField(rect, String.Empty, lwgui.perShaderData.searchString, guiStyles_ToolbarSearchTextFieldPopup);
if (EditorGUI.EndChangeCheck())
hasChanged = true;
// revert button
if (!string.IsNullOrEmpty(lwgui.perShaderData.searchString)
&& RevertableHelper.DrawRevertButton(revertButtonRect))
{
lwgui.perShaderData.searchString = string.Empty;
hasChanged = true;
GUIUtility.keyboardControl = 0;
}
// display search mode
if (GUIUtility.keyboardControl != controlId
&& string.IsNullOrEmpty(lwgui.perShaderData.searchString)
&& Event.current.type == UnityEngine.EventType.Repaint)
{
using (new EditorGUI.DisabledScope(true))
{
#if UNITY_2019_2_OR_NEWER
var disableTextRect = new Rect(rect.x, rect.y, rect.width,
guiStyles_ToolbarSearchTextFieldPopup.fixedHeight > 0.0
? guiStyles_ToolbarSearchTextFieldPopup.fixedHeight
: rect.height);
#else
var disableTextRect = rect;
disableTextRect.yMin -= 3f;
#endif
disableTextRect = guiStyles_ToolbarSearchTextFieldPopup.padding.Remove(disableTextRect);
int fontSize = EditorStyles.label.fontSize;
EditorStyles.label.fontSize = guiStyles_ToolbarSearchTextFieldPopup.fontSize;
EditorStyles.label.Draw(disableTextRect, new GUIContent(lwgui.perShaderData.searchMode.ToString()), false, false, false, false);
EditorStyles.label.fontSize = fontSize;
}
}
if (hasChanged) lwgui.perShaderData.UpdateSearchFilter();
return hasChanged;
}
#endregion
#region Context Menu
private static void EditPresetEvent(string mode, ShaderPropertyPreset presetAsset, ShaderPropertyPreset.Preset activePreset, MaterialProperty prop, LWGUI lwgui)
{
if (!VersionControlHelper.Checkout(presetAsset))
{
Debug.LogError("Can not edit the preset: " + presetAsset);
return;
}
switch (mode)
{
case "Add":
case "Update":
activePreset.AddOrUpdateIncludeExtraProperties(lwgui, prop);
break;
case "Remove":
activePreset.RemoveIncludeExtraProperties(lwgui, prop.name);
break;
}
EditorUtility.SetDirty(presetAsset);
}
public static void DoPropertyContextMenus(Rect rect, MaterialProperty prop, LWGUI lwgui)
{
if (Event.current.type != EventType.ContextClick || !rect.Contains(Event.current.mousePosition)) return;
Event.current.Use();
var propStaticData = lwgui.perShaderData.propertyDatas[prop.name];
var menus = new GenericMenu();
// 2022+ Material Varant Menus
#if UNITY_2022_1_OR_NEWER
ReflectionHelper.HandleApplyRevert(menus, prop);
#endif
// Copy
menus.AddItem(new GUIContent("Copy"), false, () =>
{
_copiedMaterial = UnityEngine.Object.Instantiate(lwgui.material);
_copiedProps.Clear();
_copiedProps.Add(prop.name);
foreach (var extraPropName in propStaticData.extraPropNames)
{
_copiedProps.Add(extraPropName);
}
// Copy Children
foreach (var childPropStaticData in propStaticData.children)
{
_copiedProps.Add(childPropStaticData.name);
foreach (var extraPropName in childPropStaticData.extraPropNames)
{
_copiedProps.Add(extraPropName);
}
foreach (var childChildPropStaticData in childPropStaticData.children)
{
_copiedProps.Add(childChildPropStaticData.name);
foreach (var extraPropName in childChildPropStaticData.extraPropNames)
{
_copiedProps.Add(extraPropName);
}
}
}
});
// Paste
GenericMenu.MenuFunction pasteAction = () =>
{
foreach (Material material in prop.targets)
{
if (!VersionControlHelper.Checkout(material))
{
Debug.LogError("Material: '" + lwgui.material.name + "' unable to write!");
return;
}
Undo.RecordObject(material, "Paste Material Properties");
var index = 0;
PastePropertyValueToMaterial(material, _copiedProps[index++], prop.name);
foreach (var extraPropName in propStaticData.extraPropNames)
{
if (index == _copiedProps.Count) break;
PastePropertyValueToMaterial(material, _copiedProps[index++], extraPropName);
}
// Paste Children
foreach (var childPropStaticData in propStaticData.children)
{
if (index == _copiedProps.Count) break;
PastePropertyValueToMaterial(material, _copiedProps[index++], childPropStaticData.name);
foreach (var extraPropName in childPropStaticData.extraPropNames)
{
if (index == _copiedProps.Count) break;
PastePropertyValueToMaterial(material, _copiedProps[index++], extraPropName);
}
foreach (var childChildPropStaticData in childPropStaticData.children)
{
if (index == _copiedProps.Count) break;
PastePropertyValueToMaterial(material, _copiedProps[index++], childChildPropStaticData.name);
foreach (var extraPropName in childChildPropStaticData.extraPropNames)
{
if (index == _copiedProps.Count) break;
PastePropertyValueToMaterial(material, _copiedProps[index++], extraPropName);
}
}
}
}
};
if (_copiedMaterial != null && _copiedProps.Count > 0 && GUI.enabled)
menus.AddItem(new GUIContent("Paste"), false, pasteAction);
else
menus.AddDisabledItem(new GUIContent("Paste"));
menus.AddSeparator("");
// Copy Display Name
menus.AddItem(new GUIContent("Copy Display Name"), false, () =>
{
EditorGUIUtility.systemCopyBuffer = propStaticData.displayName;
});
// Copy Property Names
menus.AddItem(new GUIContent("Copy Property Names"), false, () =>
{
EditorGUIUtility.systemCopyBuffer = prop.name;
foreach (var extraPropName in propStaticData.extraPropNames)
{
EditorGUIUtility.systemCopyBuffer += ", " + extraPropName;
}
});
// menus.AddSeparator("");
//
// // Add to Favorites
// menus.AddItem(new GUIContent("Add to Favorites"), false, () =>
// {
// });
//
// // Remove from Favorites
// menus.AddItem(new GUIContent("Remove from Favorites"), false, () =>
// {
// });
// Preset
if (GUI.enabled)
{
menus.AddSeparator("");
foreach (var activePresetData in lwgui.perFrameData.activePresets)
{
if (activePresetData.property == prop) continue;
var activePreset = activePresetData.preset;
var presetAsset = lwgui.perShaderData.propertyDatas[activePresetData.property.name].propertyPresetAsset;
var presetPropDisplayName = lwgui.perShaderData.propertyDatas[activePresetData.property.name].displayName;
if (activePreset.GetPropertyValue(prop.name) != null)
{
menus.AddItem(new GUIContent("Update to Preset/" + presetPropDisplayName + "/" + activePreset.presetName), false, () => EditPresetEvent("Update", presetAsset, activePreset, prop, lwgui));
menus.AddItem(new GUIContent("Remove from Preset/" + presetPropDisplayName + "/" + activePreset.presetName), false, () => EditPresetEvent("Remove", presetAsset, activePreset, prop, lwgui));
}
else
{
menus.AddItem(new GUIContent("Add to Preset/" + presetPropDisplayName + "/" + activePreset.presetName), false, () => EditPresetEvent("Add", presetAsset, activePreset, prop, lwgui));
}
}
}
menus.ShowAsContext();
}
#endregion
}
}