using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
namespace OM.Editor
{
///
/// A static utility class for drawing serialized properties and editor elements in Unity,
/// as well as reflection and script handling tools for the Editor.
///
public static class OMEditorUtility
{
///
/// Draws all visible properties of a SerializedProperty using IMGUI.
///
public static void DrawAllProperties(this SerializedProperty property, bool enterChildren = true)
{
EditorGUI.indentLevel++;
var currentProperty = property.Copy();
var startDepth = currentProperty.depth;
while (currentProperty.NextVisible(enterChildren) && currentProperty.depth > startDepth)
{
enterChildren = false;
if (currentProperty.name == "m_Script")
continue;
EditorGUILayout.PropertyField(currentProperty, true);
}
EditorGUI.indentLevel--;
}
///
/// Draws all visible properties in a given Rect (manual layout).
///
public static void DrawAllProperties(this SerializedProperty property, Rect position, bool enterChildren = true)
{
if (property == null)
{
EditorGUI.HelpBox(position, "SerializedProperty is null", MessageType.Error);
return;
}
EditorGUI.indentLevel++;
var currentProperty = property.Copy();
var startDepth = currentProperty.depth;
while (currentProperty.NextVisible(enterChildren) && currentProperty.depth > startDepth)
{
enterChildren = false;
if (currentProperty.name == "m_Script")
continue;
EditorGUI.PropertyField(position, currentProperty, true);
position.y += EditorGUI.GetPropertyHeight(currentProperty, true);
}
EditorGUI.indentLevel--;
}
///
/// Calculates the total height required to draw all visible child properties.
///
public static float GetHeightOfAllProperties(this SerializedProperty property, bool enterChildren = true)
{
if (property == null)
return 20;
float height = 20;
var currentProperty = property.Copy();
var startDepth = currentProperty.depth;
while (currentProperty.NextVisible(enterChildren) && currentProperty.depth > startDepth)
{
enterChildren = false;
if (currentProperty.name == "m_Script")
continue;
height += EditorGUI.GetPropertyHeight(currentProperty, true);
}
return height;
}
///
/// Draws all properties of a SerializedObject inside a VisualElement using IMGUI.
///
public static void DrawAllFieldsInSerializedObject(VisualElement root, SerializedObject serializedObject, Action onChanged = null)
{
var imguiContainer = new IMGUIContainer(() =>
{
if (serializedObject.targetObject == null) return;
serializedObject.Update();
serializedObject.GetIterator().DrawAllProperties();
if (GUI.changed)
onChanged?.Invoke();
serializedObject.ApplyModifiedProperties();
});
imguiContainer.style.marginTop = 5;
imguiContainer.style.marginBottom = 5;
root.Add(imguiContainer);
}
///
/// Draws all fields of a SerializedObject using IMGUI inside the provided VisualElement.
///
public static void DrawAllFields(this SerializedObject serializedObject, VisualElement root, Action onChanged = null)
{
var imguiContainer = new IMGUIContainer(() =>
{
if (serializedObject.targetObject == null) return;
serializedObject.Update();
serializedObject.GetIterator().DrawAllProperties();
if (GUI.changed)
onChanged?.Invoke();
serializedObject.ApplyModifiedProperties();
});
imguiContainer.style.marginTop = 5;
imguiContainer.style.marginBottom = 5;
imguiContainer.style.marginLeft = -5;
root.Add(imguiContainer);
}
///
/// Draws elements in a grid layout using IMGUI inside a VisualElement.
///
public static void DrawInGrid(VisualElement root, float windowWidth, int count, Action itemCallback)
{
root.Add(new IMGUIContainer(() =>
{
const float buttonWidth = 60;
var buttonsCountInRow = (int)(windowWidth / buttonWidth);
GUILayout.BeginHorizontal();
for (var i = 0; i < count; i++)
{
if (i % buttonsCountInRow == 0)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
itemCallback?.Invoke(i);
}
GUILayout.EndHorizontal();
}));
}
///
/// Draws all MonoBehaviour objects of type T in the current scene in a grid layout.
///
public static void DrawAllObjectsInSceneInGrid(this EditorWindow editorWindow, ref IMGUIContainer container, float buttonWidth, Action itemCreate) where T : MonoBehaviour
{
container.onGUIHandler += () =>
{
var buttonsCountInRow = (int)(editorWindow.position.width / buttonWidth);
var objects = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None);
GUILayout.BeginHorizontal();
for (var i = 0; i < objects.Length; i++)
{
if (i % buttonsCountInRow == 0)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
itemCreate?.Invoke(objects[i]);
}
GUILayout.EndHorizontal();
};
}
///
/// Draws objects returned by getObjects in a grid layout using IMGUI.
///
public static void DrawObjectsInGrid(this EditorWindow editorWindow, ref IMGUIContainer container, float buttonWidth, Func getObjects, Action itemCreate)
{
container.onGUIHandler += () =>
{
var buttonsCountInRow = (int)(editorWindow.position.width / buttonWidth);
var objects = getObjects.Invoke();
if (objects == null) return;
GUILayout.BeginHorizontal();
for (var i = 0; i < objects.Length; i++)
{
if (i % buttonsCountInRow == 0)
{
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
}
itemCreate?.Invoke(objects[i]);
}
GUILayout.EndHorizontal();
};
}
///
/// Finds a MonoScript asset by its type name and opens it in the default script editor.
///
public static void FindScriptInAssetsAndOpen(object target)
{
if (target == null) return;
var script = target.GetType().Name;
var guids = AssetDatabase.FindAssets(script);
if (guids.Length == 0)
{
Debug.LogError("Script not found in assets");
return;
}
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
var asset = AssetDatabase.LoadAssetAtPath(path);
AssetDatabase.OpenAsset(asset);
}
///
/// Iterates through all values of an enum type.
///
public static IEnumerable LoopThroughEnum() where T : Enum
{
var list = new List();
foreach (T value in Enum.GetValues(typeof(T)))
list.Add(value);
return list;
}
///
/// Searches for a script asset by name and returns it if found.
///
public static bool GetScriptByName(string scriptName, out MonoScript resultScript)
{
var guids = AssetDatabase.FindAssets(scriptName + " t:Script");
if (guids.Length == 0)
{
Debug.LogWarning("Script not found!");
resultScript = null;
return false;
}
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
resultScript = AssetDatabase.LoadAssetAtPath(path);
return resultScript != null;
}
///
/// Opens a C# script file by its class name using Unity's asset database.
///
public static void OpenScriptInEditorByName(string scriptName)
{
if (GetScriptByName(scriptName, out var script))
{
AssetDatabase.OpenAsset(script);
}
else
{
Debug.LogError($"Script {scriptName} not found");
}
}
///
/// Opens a MonoScript asset in the default script editor.
///
public static void OpenScriptInEditor(MonoScript script)
{
AssetDatabase.OpenAsset(script);
}
}
}