首次提交

This commit is contained in:
Bob.Song
2026-03-05 18:07:55 +08:00
commit e125bb869e
4534 changed files with 563920 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d8e44b0f278584fbfa8ae00d01b2ce3f
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
{
"name": "VHierarchy",
"rootNamespace": "",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2c3f48364a5004fd3a152fbdf5fea703
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 67e949be20d3641adbc9494ed5bd764e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,62 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using Type = System.Type;
using static VHierarchy.VHierarchyData;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
[FilePath("Library/vHierarchy Cache.asset", FilePathAttribute.Location.ProjectFolder)]
public class VHierarchyCache : ScriptableSingleton<VHierarchyCache>
{
// used for finding SceneData and SceneIdMap for objects that were moved out of their original scene
public SerializableDictionary<int, string> originalSceneGuids_byInstanceId = new SerializableDictionary<int, string>();
// used as cache for converting GlobalID to InstanceID and as a way to find GameObjectData for prefabs in playmode (when prefabs produce invalid GlobalIDs)
public SerializableDictionary<string, SceneIdMap> sceneIdMaps_bySceneGuid = new SerializableDictionary<string, SceneIdMap>();
// used for fetching icons set inside prefab instances in playmode (when prefabs produce invalid GlobalIDs)
public SerializableDictionary<int, GlobalID> prefabInstanceGlobalIds_byInstanceIds = new SerializableDictionary<int, GlobalID>();
[System.Serializable]
public class SceneIdMap
{
public SerializableDictionary<int, GlobalID> globalIds_byInstanceId = new SerializableDictionary<int, GlobalID>();
public int instanceIdsHash;
public int globalIdsHash;
}
public static void Clear()
{
instance.originalSceneGuids_byInstanceId.Clear();
instance.sceneIdMaps_bySceneGuid.Clear();
instance.Save(true);
}
// public static void Save() => instance.Save(true); // cache is never saved to disk, it just needs to survive domain reloads
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3fd3b966dd497472d86df0d7c9271088
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
// this file was present in a previus version and is supposed to be deleted now
// but asset store update delivery system doesn't allow deleting files
// so instead this file is now emptied
// feel free to delete it if you want

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d51d8117d96b64eaa9a83667bf4297d6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,575 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using Type = System.Type;
using static VHierarchy.VHierarchyData;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
public class VHierarchyComponentWindow : EditorWindow
{
void OnGUI()
{
if (!component) { Close(); return; } // todo script components break on playmode
void background()
{
position.SetPos(0, 0).Draw(GUIColors.windowBackground);
}
void outline()
{
if (Application.platform == RuntimePlatform.OSXEditor) return;
position.SetPos(0, 0).DrawOutline(Greyscale(.1f));
}
void header()
{
var headerRect = ExpandWidthLabelRect(18).Resize(-1).AddWidthFromMid(6);
var pinButtonRect = headerRect.SetWidthFromRight(17).SetHeightFromMid(17).Move(-21, .5f);
var closeButtonRect = headerRect.SetWidthFromRight(16).SetHeightFromMid(16).Move(-3, .5f);
var backgroundColor = isDarkTheme ? Greyscale(.25f) : GUIColors.windowBackground;
void startDragging()
{
if (isResizingVertically) return;
if (isResizingHorizontally) return;
if (isDragged) return;
if (!curEvent.isMouseDrag) return;
if (!headerRect.IsHovered()) return;
isDragged = true;
dragStartMousePos = EditorGUIUtility.GUIToScreenPoint(curEvent.mousePosition);
dragStartWindowPos = position.position;
isPinned = true;
if (floatingInstance == this)
floatingInstance = null;
EditorApplication.RepaintHierarchyWindow();
}
void updateDragging()
{
if (!isDragged) return;
var draggedPosition = dragStartWindowPos + EditorGUIUtility.GUIToScreenPoint(curEvent.mousePosition) - dragStartMousePos;
if (!curEvent.isRepaint)
position = position.SetPos(draggedPosition);
EditorGUIUtility.hotControl = EditorGUIUtility.GetControlID(FocusType.Passive);
}
void stopDragging()
{
if (!isDragged) return;
if (!curEvent.isMouseUp) return;
isDragged = false;
EditorGUIUtility.hotControl = 0;
}
void background()
{
headerRect.Draw(backgroundColor);
headerRect.SetHeightFromBottom(1).Draw(isDarkTheme ? Greyscale(.2f) : Greyscale(.7f));
}
void icon()
{
var iconRect = headerRect.SetWidth(20).MoveX(14).MoveY(-1);
GUI.Label(iconRect, VHierarchy.GetComponentIcon(component));
}
void toggle()
{
var toggleRect = headerRect.MoveX(36).SetSize(20, 20);
var pi_enabled = component.GetType().GetProperty("enabled") ??
component.GetType().BaseType?.GetProperty("enabled") ??
component.GetType().BaseType?.BaseType?.GetProperty("enabled") ??
component.GetType().BaseType?.BaseType?.BaseType?.GetProperty("enabled");
if (pi_enabled == null) return;
var enabled = (bool)pi_enabled.GetValue(component);
if (GUI.Toggle(toggleRect, enabled, "") == enabled) return;
component.RecordUndo();
pi_enabled.SetValue(component, !enabled);
}
void name()
{
var nameRect = headerRect.MoveX(54).MoveY(-1);
var s = VHierarchy.GetComponentName(component);
if (isPinned)
s += " of " + component.gameObject.name;
SetLabelBold();
GUI.Label(nameRect, s);
ResetLabelStyle();
}
void nameCurtain()
{
var flatColorRect = headerRect.SetX(pinButtonRect.x + 3).SetXMax(headerRect.xMax);
var gradientRect = headerRect.SetXMax(flatColorRect.x).SetWidthFromRight(30);
flatColorRect.Draw(backgroundColor);
gradientRect.DrawCurtainLeft(backgroundColor);
}
void pinButton()
{
if (!isPinned && closeButtonRect.IsHovered()) return;
var normalColor = isDarkTheme ? Greyscale(.65f) : Greyscale(.8f);
var hoveredColor = isDarkTheme ? Greyscale(.9f) : normalColor;
var activeColor = Color.white;
SetGUIColor(isPinned ? activeColor : pinButtonRect.IsHovered() ? hoveredColor : normalColor);
GUI.Label(pinButtonRect, EditorGUIUtility.IconContent("pinned"));
ResetGUIColor();
SetGUIColor(Color.clear);
var clicked = GUI.Button(pinButtonRect, "");
ResetGUIColor();
if (!clicked) return;
isPinned = !isPinned;
if (isPinned && floatingInstance == this)
floatingInstance = null;
if (!isPinned && !floatingInstance)
floatingInstance = this;
EditorApplication.RepaintHierarchyWindow();
}
void closeButton()
{
SetGUIColor(Color.clear);
if (GUI.Button(closeButtonRect, ""))
Close();
ResetGUIColor();
var normalColor = isDarkTheme ? Greyscale(.65f) : Greyscale(.35f);
var hoveredColor = isDarkTheme ? Greyscale(.9f) : normalColor;
SetGUIColor(closeButtonRect.IsHovered() ? hoveredColor : normalColor);
GUI.Label(closeButtonRect, EditorGUIUtility.IconContent("CrossIcon"));
ResetGUIColor();
if (isPinned) return;
var escRect = closeButtonRect.Move(-22, -1).SetWidth(70);
SetGUIEnabled(false);
if (closeButtonRect.IsHovered())
GUI.Label(escRect, "Esc");
ResetGUIEnabled();
}
startDragging();
updateDragging();
stopDragging();
background();
icon();
toggle();
name();
nameCurtain();
pinButton();
closeButton();
}
void body()
{
EditorGUIUtility.labelWidth = (this.position.width * .4f).Max(120);
scrollPosition = EditorGUILayout.BeginScrollView(Vector2.up * scrollPosition).y;
BeginIndent(17);
editor?.OnInspectorGUI();
updateHeight();
EndIndent(1);
EditorGUILayout.EndScrollView();
EditorGUIUtility.labelWidth = 0;
}
void updateHeight()
{
ExpandWidthLabelRect(height: -5);
if (!curEvent.isRepaint) return;
if (isResizingVertically) return;
targetHeight = lastRect.y + 30;
position = position.SetHeight(targetHeight.Min(maxHeight));
prevHeight = position.height;
}
void updatePosition()
{
if (!curEvent.isLayout) return;
void calcDeltaTime()
{
deltaTime = (float)(EditorApplication.timeSinceStartup - lastLayoutTime);
if (deltaTime > .05f)
deltaTime = .0166f;
lastLayoutTime = EditorApplication.timeSinceStartup;
}
void resetCurPos()
{
if (currentPosition != default && !isPinned) return;
currentPosition = position.position; // position.position is always int, which can't be used for lerping
}
void lerpCurPos()
{
if (isPinned) return;
var speed = 9;
SmoothDamp(ref currentPosition, targetPosition, speed, ref positionDeriv, deltaTime);
// Lerp(ref currentPosition, targetPosition, speed, deltaTime);
}
void setCurPos()
{
if (isPinned) return;
position = position.SetPos(currentPosition);
}
calcDeltaTime();
resetCurPos();
lerpCurPos();
setCurPos();
}
void closeOnEscape()
{
if (!curEvent.isKeyDown) return;
if (curEvent.keyCode != KeyCode.Escape) return;
Close();
}
void horizontalResize()
{
var showingScrollbar = targetHeight > maxHeight;
var resizeArea = this.position.SetPos(0, 0).SetWidthFromRight(showingScrollbar ? 3 : 5).AddHeightFromBottom(-20);
void startResize()
{
if (isDragged) return;
if (isResizingHorizontally) return;
if (!curEvent.isMouseDown && !curEvent.isMouseDrag) return;
if (!resizeArea.IsHovered()) return;
isResizingHorizontally = true;
resizeStartMousePos = curEvent.mousePosition_screenSpace;
resizeStartWindowSize = this.position.size;
}
void updateResize()
{
if (!isResizingHorizontally) return;
var resizedWidth = resizeStartWindowSize.x + curEvent.mousePosition_screenSpace.x - resizeStartMousePos.x;
var width = resizedWidth.Max(300);
if (!curEvent.isRepaint)
position = position.SetWidth(width);
EditorGUIUtility.hotControl = EditorGUIUtility.GetControlID(FocusType.Passive);
// GUI.focused
}
void stopResize()
{
if (!isResizingHorizontally) return;
if (!curEvent.isMouseUp) return;
isResizingHorizontally = false;
EditorGUIUtility.hotControl = 0;
}
EditorGUIUtility.AddCursorRect(resizeArea, MouseCursor.ResizeHorizontal);
startResize();
updateResize();
stopResize();
}
void verticalResize()
{
var resizeArea = this.position.SetPos(0, 0).SetHeightFromBottom(5);
void startResize()
{
if (isDragged) return;
if (isResizingVertically) return;
if (!curEvent.isMouseDown && !curEvent.isMouseDrag) return;
if (!resizeArea.IsHovered()) return;
isResizingVertically = true;
resizeStartMousePos = curEvent.mousePosition_screenSpace;
resizeStartWindowSize = this.position.size;
}
void updateResize()
{
if (!isResizingVertically) return;
var resizedHeight = resizeStartWindowSize.y + curEvent.mousePosition_screenSpace.y - resizeStartMousePos.y;
var height = resizedHeight.Min(targetHeight).Max(50);
if (!curEvent.isRepaint)
position = position.SetHeight(height);
maxHeight = height;
EditorGUIUtility.hotControl = EditorGUIUtility.GetControlID(FocusType.Passive);
// GUI.focused
}
void stopResize()
{
if (!isResizingVertically) return;
if (!curEvent.isMouseUp) return;
isResizingVertically = false;
EditorGUIUtility.hotControl = 0;
}
EditorGUIUtility.AddCursorRect(resizeArea, MouseCursor.ResizeVertical);
startResize();
updateResize();
stopResize();
}
background();
outline();
horizontalResize();
verticalResize();
header();
Space(3);
body();
Space(7);
updatePosition();
closeOnEscape();
if (!isPinned)
Repaint();
}
public Vector2 targetPosition;
public Vector2 currentPosition;
Vector2 positionDeriv;
float deltaTime;
double lastLayoutTime;
bool isDragged;
Vector2 dragStartMousePos;
Vector2 dragStartWindowPos;
public bool isResizingHorizontally;
public bool isResizingVertically;
public Vector2 resizeStartMousePos;
public Vector2 resizeStartWindowSize;
public float scrollPosition;
public float targetHeight;
public float maxHeight;
public float prevHeight;
void OnLostFocus()
{
if (isPinned) return;
if (curEvent.holdingAlt && EditorWindow.focusedWindow.GetType().Name == "SceneHierarchyWindow")
CloseNextFrameIfNotRefocused();
else
Close();
}
void CloseNextFrameIfNotRefocused()
{
EditorApplication.delayCall += () => { if (EditorWindow.focusedWindow != this) Close(); };
}
public bool isPinned;
public void Init(Component component)
{
if (editor)
editor.DestroyImmediate();
this.component = component;
this.editor = Editor.CreateEditor(component);
}
void OnDestroy()
{
editor?.DestroyImmediate();
editor = null;
component = null;
EditorPrefs.SetFloat("vHierarchy-componentWindowWidth", position.width);
}
public Component component;
public Editor editor;
public static void CreateFloatingInstance(Vector2 position)
{
floatingInstance = ScriptableObject.CreateInstance<VHierarchyComponentWindow>();
floatingInstance.ShowPopup();
floatingInstance.maxHeight = EditorGUIUtility.GetMainWindowPosition().height * .7f;
var savedWidth = EditorPrefs.GetFloat("vHierarchy-componentWindowWidth", minWidth);
var width = savedWidth.Max(minWidth);
floatingInstance.position = Rect.zero.SetPos(position).SetWidth(width).SetHeight(200);
floatingInstance.prevHeight = floatingInstance.position.height;
floatingInstance.targetPosition = position;
}
public static VHierarchyComponentWindow floatingInstance;
public static float minWidth => 300;
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4b48d49a631ab443990f28938cbdedb8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
public class VHierarchyData : ScriptableObject, ISerializationCallbackReceiver
{
public SerializableDictionary<string, SceneData> sceneDatas_byGuid = new SerializableDictionary<string, SceneData>();
[System.Serializable]
public class SceneData
{
public SerializableDictionary<GlobalID, GameObjectData> goDatas_byGlobalId = new SerializableDictionary<GlobalID, GameObjectData>();
}
[System.Serializable]
public class GameObjectData
{
public int colorIndex;
public string iconNameOrGuid = ""; // name for buildin icons, guid for custom ones
[System.NonSerialized] // set in GetGameObjectData
public SceneData sceneData;
}
public void OnBeforeSerialize() => VHierarchy.firstDataCacheLayer.Clear();
public void OnAfterDeserialize() => VHierarchy.firstDataCacheLayer.Clear();
[CustomEditor(typeof(VHierarchyData))]
class Editor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var style = new GUIStyle(EditorStyles.label) { wordWrap = true };
SetGUIEnabled(false);
BeginIndent(0);
Space(10);
EditorGUILayout.LabelField("This file contains data about which icons and colors are assigned to objects", style);
Space(6);
GUILayout.Label("If there are multiple people working on the project, you might want to store this data in scenes to avoid merge conflicts. To do that, create a script that inherits from VHierarchy.VHierarchyDataComponent and add it to any object in the scene", style);
EndIndent(10);
ResetGUIEnabled();
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3a9752b0c8e144801967e6897679604b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,95 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditor.Experimental.SceneManagement;
using Type = System.Type;
using static VHierarchy.VHierarchyData;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
[ExecuteInEditMode]
public abstract class VHierarchyDataComponent : MonoBehaviour, ISerializationCallbackReceiver
{
public void Awake()
{
void register()
{
VHierarchy.dataComponents_byScene[gameObject.scene] = this;
}
void handleSceneDuplication()
{
if (sceneData == null) return;
if (!sceneData.goDatas_byGlobalId.Any()) return;
var curSceneGuid = gameObject.scene.path.ToGuid();
var dataSceneGuid = sceneData.goDatas_byGlobalId.Keys.First().guid;
if (curSceneGuid == dataSceneGuid) return;
var newDic = new SerializableDictionary<GlobalID, GameObjectData>();
foreach (var kvp in sceneData.goDatas_byGlobalId)
newDic[new GlobalID(kvp.Key.ToString().Replace(dataSceneGuid, curSceneGuid))] = kvp.Value;
sceneData.goDatas_byGlobalId = newDic;
EditorSceneManager.MarkSceneDirty(gameObject.scene);
EditorSceneManager.SaveScene(gameObject.scene);
}
register();
handleSceneDuplication();
}
public SceneData sceneData;
public void OnBeforeSerialize() => VHierarchy.firstDataCacheLayer.Clear();
public void OnAfterDeserialize() => VHierarchy.firstDataCacheLayer.Clear();
[CustomEditor(typeof(VHierarchyDataComponent), true)]
class Editor : UnityEditor.Editor
{
public override void OnInspectorGUI()
{
var style = EditorStyles.label;
style.wordWrap = true;
SetGUIEnabled(false);
BeginIndent(0);
Space(4);
EditorGUILayout.LabelField("This component stores vHierarchy icons and colors that are assigned to objects in this scene", style);
Space(2);
EndIndent(10);
ResetGUIEnabled();
}
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9e20c7ea1a24b4a899ba82e98ad2b375
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
// this file was present in a previus version and is supposed to be deleted now
// but asset store update delivery system doesn't allow deleting files
// so instead this file is now emptied
// feel free to delete it if you want

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8710ada63f66c4909ab73d206f31e954
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cd278e4ae9a8649f59f016c7d739ce1a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,353 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
public class VHierarchyLightingWindow : EditorWindow
{
void OnGUI()
{
void updateSize()
{
var r = ExpandWidthLabelRect();
if (!curEvent.isRepaint) return;
var curHeight = r.y;
this.position = position.SetWidth(initWidth).SetHeight(curHeight);
this.minSize = Vector2.zero;
this.maxSize = Vector2.one * 123212;
}
void header()
{
var height = 22f;
var headerRect = Rect.zero.SetHeight(height).SetWidth(position.width);
var pinButtonRect = headerRect.SetWidthFromRight(17).SetHeightFromMid(17).Move(-21, .5f);
var closeButtonRect = headerRect.SetWidthFromRight(16).SetHeightFromMid(16).Move(-3, .5f);
void startDragging()
{
if (isDragged) return;
if (!curEvent.isMouseDrag) return;
if (!headerRect.IsHovered()) return;
isDragged = true;
dragStartMousePos = EditorGUIUtility.GUIToScreenPoint(curEvent.mousePosition);
dragStartWindowPos = position.position;
isPinned = true;
EditorApplication.RepaintHierarchyWindow();
}
void updateDragging()
{
if (!isDragged) return;
if (!curEvent.isRepaint) // ??
position = position.SetPos(dragStartWindowPos + EditorGUIUtility.GUIToScreenPoint(curEvent.mousePosition) - dragStartMousePos);
EditorGUIUtility.hotControl = EditorGUIUtility.GetControlID(FocusType.Passive);
}
void stopDragging()
{
if (!isDragged) return;
if (!curEvent.isMouseUp) return;
isDragged = false;
EditorGUIUtility.hotControl = 0;
}
void background()
{
headerRect.Draw(EditorGUIUtility.isProSkin ? Greyscale(.185f) : Greyscale(.7f));
}
void title_()
{
SetGUIColor(Greyscale(.8f));
SetLabelAlignmentCenter();
GUI.Label(headerRect, "Lighting");
ResetLabelStyle();
ResetGUIColor();
}
void pinButton()
{
if (!isPinned && closeButtonRect.IsHovered()) return;
var normalColor = isDarkTheme ? Greyscale(.65f) : Greyscale(.8f);
var hoveredColor = isDarkTheme ? Greyscale(.9f) : normalColor;
var activeColor = Color.white;
SetGUIColor(isPinned ? activeColor : pinButtonRect.IsHovered() ? hoveredColor : normalColor);
GUI.Label(pinButtonRect, EditorGUIUtility.IconContent("pinned"));
ResetGUIColor();
SetGUIColor(Color.clear);
var clicked = GUI.Button(pinButtonRect, "");
ResetGUIColor();
if (!clicked) return;
isPinned = !isPinned;
}
void closeButton()
{
SetGUIColor(Color.clear);
if (GUI.Button(closeButtonRect, "") || (curEvent.isKeyDown && curEvent.keyCode == KeyCode.Escape))
Close();
ResetGUIColor();
var normalColor = isDarkTheme ? Greyscale(.65f) : Greyscale(.35f);
var hoveredColor = isDarkTheme ? Greyscale(.9f) : normalColor;
SetGUIColor(closeButtonRect.IsHovered() ? hoveredColor : normalColor);
GUI.Label(closeButtonRect, EditorGUIUtility.IconContent("CrossIcon"));
ResetGUIColor();
if (isPinned) return;
var escRect = closeButtonRect.Move(-22, -1).SetWidth(70);
SetGUIEnabled(false);
if (closeButtonRect.IsHovered())
GUI.Label(escRect, "Esc");
ResetGUIEnabled();
}
startDragging();
updateDragging();
stopDragging();
background();
title_();
pinButton();
closeButton();
Space(height);
}
void directionalLight()
{
var light = FindObjects<Light>().Where(r => r.type == LightType.Directional && r.gameObject.scene == EditorSceneManager.GetActiveScene()).FirstOrDefault();
if (!light) return;
light.RecordUndo();
light.transform.RecordUndo();
ObjectFieldWidhoutPicker("Directional Light", light);
Space(2);
BeginIndent(8);
EditorGUIUtility.labelWidth += 2;
var rotX = light.transform.eulerAngles.x.Loop(-180, 180).Round();
var rotY = light.transform.eulerAngles.y.Loop(-180, 180).Round();
rotX = EditorGUILayout.Slider("Rotation X", rotX, 0, 90);
rotY = EditorGUILayout.Slider("Rotation Y", rotY, -179, 180);
if (light.transform.rotation != Quaternion.Euler(rotX, rotY, light.transform.eulerAngles.z))
light.transform.rotation = Quaternion.Euler(rotX, rotY, light.transform.eulerAngles.z);
Space(3);
light.intensity = EditorGUILayout.Slider("Intensity", light.intensity, 0, 2);
light.color = SmallColorField(ExpandWidthLabelRect().AddWidthFromMid(-1).MoveX(-.5f), "Color", light.color, true);
EndIndent();
}
void ambientLight()
{
RenderSettings.ambientMode = (UnityEngine.Rendering.AmbientMode)EditorGUILayout.IntPopup("Ambient Light", (int)RenderSettings.ambientMode, new[] { "\u2009Skybox", "\u2009Gradient", "\u2009Color" }, new[] { 0, 1, 3 });
foreach (var r in FindObjects<RenderSettings>())
r.RecordUndo();
Space(2);
BeginIndent(8);
EditorGUIUtility.labelWidth += 4;
if (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Flat)
{
Color.RGBToHSV(RenderSettings.ambientSkyColor, out float h, out float s, out float v);
v = EditorGUILayout.Slider("Intensity", v, .01f, 2);
RenderSettings.ambientSkyColor = Color.HSVToRGB(h, s, v, true);
RenderSettings.ambientSkyColor = SmallColorField("Color", RenderSettings.ambientSkyColor, false, true);
}
if (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Skybox)
RenderSettings.ambientIntensity = EditorGUILayout.Slider("Intensity", RenderSettings.ambientIntensity, 0, 2);
if (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Trilight)
{
RenderSettings.ambientSkyColor = SmallColorField("Color Sky", RenderSettings.ambientSkyColor, false, true);
RenderSettings.ambientEquatorColor = SmallColorField("Color Horizon", RenderSettings.ambientEquatorColor, false, true);
RenderSettings.ambientGroundColor = SmallColorField("Color Ground", RenderSettings.ambientGroundColor, false, true);
}
EndIndent();
}
void fog()
{
var mode = EditorGUILayout.IntPopup("Fog", RenderSettings.fog ? (int)RenderSettings.fogMode : 0, new[] { "\u2009Off", "\u2009Linear", "\u2009Exponential", "\u2009Exponential Squared" }, new[] { 0, 1, 2, 3 });
if (RenderSettings.fog = mode != 0)
RenderSettings.fogMode = (FogMode)mode;
if (!RenderSettings.fog) return;
Space(2);
BeginIndent(8);
EditorGUIUtility.labelWidth += 4;
if (RenderSettings.fogMode == FogMode.Linear)
{
RenderSettings.fogStartDistance = EditorGUILayout.FloatField("Start", RenderSettings.fogStartDistance);
RenderSettings.fogEndDistance = EditorGUILayout.FloatField("End", RenderSettings.fogEndDistance);
}
else
RenderSettings.fogDensity = ExpSlider(ExpandWidthLabelRect().AddWidthFromRight(1.5f), "Density", RenderSettings.fogDensity, 0, .05f);
RenderSettings.fogColor = SmallColorField("Color", RenderSettings.fogColor, true, false);
EndIndent();
}
header();
BeginIndent(6);
EditorGUIUtility.labelWidth = 115;
Space(11);
directionalLight();
Space(18);
ambientLight();
Space(18);
fog();
EndIndent(6);
Space(21);
updateSize();
if (Application.platform != RuntimePlatform.OSXEditor)
position.SetPos(0, 0).DrawOutline(Greyscale(.1f));
EditorGUIUtility.labelWidth = 0;
Repaint();
}
bool isDragged;
Vector2 dragStartMousePos;
Vector2 dragStartWindowPos;
void OnLostFocus()
{
if (isPinned) return;
Close();
}
public bool isPinned;
public static void CreateInstance(Vector2 position)
{
instance = ScriptableObject.CreateInstance<VHierarchyLightingWindow>();
instance.ShowPopup();
instance.position = Rect.zero.SetPos(position).SetSize(initWidth, initHeight);
instance.minSize = Vector2.zero;
instance.maxSize = Vector2.one * 123212;
}
public static VHierarchyLightingWindow instance;
static float initWidth => 250;
static float initHeight => 320;
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 25324ddc1ebdc4ee5b1d9902a8efafa7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,151 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
class VHierarchyMenu
{
public static bool componentMinimapEnabled { get => EditorPrefsCached.GetBool("vHierarchy-componentMinimapEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-componentMinimapEnabled", value); }
public static bool hierarchyLinesEnabled { get => EditorPrefsCached.GetBool("vHierarchy-hierarchyLinesEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-hierarchyLinesEnabled", value); }
public static bool minimalModeEnabled { get => EditorPrefsCached.GetBool("vHierarchy-minimalModeEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-minimalModeEnabled", value); }
public static bool zebraStripingEnabled { get => EditorPrefsCached.GetBool("vHierarchy-zebraStripingEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-zebraStripingEnabled", value); }
public static bool activationToggleEnabled { get => EditorPrefsCached.GetBool("vHierarchy-acctivationToggleEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-acctivationToggleEnabled", value); }
public static bool collapseAllButtonEnabled { get => EditorPrefsCached.GetBool("vHierarchy-collapseAllButtonEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-collapseAllButtonEnabled", value); }
public static bool editLightingButtonEnabled { get => EditorPrefsCached.GetBool("vHierarchy-editLightingButtonEnabled", false); set => EditorPrefsCached.SetBool("vHierarchy-editLightingButtonEnabled", value); }
public static bool toggleActiveEnabled { get => EditorPrefsCached.GetBool("vHierarchy-toggleActiveEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-toggleActiveEnabled", value); }
public static bool focusEnabled { get => EditorPrefsCached.GetBool("vHierarchy-focusEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-focusEnabled", value); }
public static bool deleteEnabled { get => EditorPrefsCached.GetBool("vHierarchy-deleteEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-deleteEnabled", value); }
public static bool toggleExpandedEnabled { get => EditorPrefsCached.GetBool("vHierarchy-toggleExpandedEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-toggleExpandedEnabled", value); }
public static bool collapseEverythingElseEnabled { get => EditorPrefsCached.GetBool("vHierarchy-collapseEverythingElseEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-collapseEverythingElseEnabled", value); }
public static bool collapseEverythingEnabled { get => EditorPrefsCached.GetBool("vHierarchy-collapseEverythingEnabled", true); set => EditorPrefsCached.SetBool("vHierarchy-collapseEverythingEnabled", value); }
public static bool pluginDisabled { get => EditorPrefsCached.GetBool("vHierarchy-pluginDisabled", false); set => EditorPrefsCached.SetBool("vHierarchy-pluginDisabled", value); }
const string dir = "Tools/vHierarchy/";
const string componentMinimap = dir + "Component minimap";
const string hierarchyLines = dir + "Hierarchy lines";
const string minimalMode = dir + "Minimal mode";
const string zebraStriping = dir + "Zebra striping";
const string activationToggle = dir + "Activation toggle";
const string collapseAllButton = dir + "Collapse All button";
const string editLightingButton = dir + "Edit Lighting button";
const string toggleActive = dir + "A to toggle active";
const string focus = dir + "F to focus";
const string delete = dir + "X to delete";
const string toggleExpanded = dir + "E to expand or collapse";
const string collapseEverythingElse = dir + "Shift-E to isolate";
const string collapseEverything = dir + "Ctrl-Shift-E to collapse all";
const string disablePlugin = dir + "Disable vHierarchy";
[MenuItem(dir + "Features", false, 1)] static void daasddsas() { }
[MenuItem(dir + "Features", true, 1)] static bool dadsdasas123() => false;
[MenuItem(componentMinimap, false, 2)] static void daadsdsadasdadsas() { componentMinimapEnabled = !componentMinimapEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(componentMinimap, true, 2)] static bool dadsadasddasadsas() { Menu.SetChecked(componentMinimap, componentMinimapEnabled); return !pluginDisabled; }
[MenuItem(hierarchyLines, false, 3)] static void dadsadadsadadasss() { hierarchyLinesEnabled = !hierarchyLinesEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(hierarchyLines, true, 3)] static bool dadsaddasdasaasddsas() { Menu.SetChecked(hierarchyLines, hierarchyLinesEnabled); return !pluginDisabled; }
[MenuItem(minimalMode, false, 4)] static void dadsadadasdsdasadadasss() { minimalModeEnabled = !minimalModeEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(minimalMode, true, 4)] static bool dadsaddadsasdadsasaasddsas() { Menu.SetChecked(minimalMode, minimalModeEnabled); return !pluginDisabled; }
[MenuItem(zebraStriping, false, 5)] static void dadsadadadssadsadass() { zebraStripingEnabled = !zebraStripingEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(zebraStriping, true, 5)] static bool dadsaddadaadsssadsaasddsas() { Menu.SetChecked(zebraStriping, zebraStripingEnabled); return !pluginDisabled; }
[MenuItem(activationToggle, false, 6)] static void daadsdsadadsasdadsas() { activationToggleEnabled = !activationToggleEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(activationToggle, true, 6)] static bool dadsadasdsaddasadsas() { Menu.SetChecked(activationToggle, activationToggleEnabled); return !pluginDisabled; }
[MenuItem(collapseAllButton, false, 7)] static void daadsdsadadsadadsas() { collapseAllButtonEnabled = !collapseAllButtonEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(collapseAllButton, true, 7)] static bool dadsadasdsaddasdsas() { Menu.SetChecked(collapseAllButton, collapseAllButtonEnabled); return !pluginDisabled; }
[MenuItem(editLightingButton, false, 8)] static void daadsdsasdadadsadadsas() { editLightingButtonEnabled = !editLightingButtonEnabled; EditorApplication.RepaintHierarchyWindow(); }
[MenuItem(editLightingButton, true, 8)] static bool dadsadasdsadsaddasdsas() { Menu.SetChecked(editLightingButton, editLightingButtonEnabled); return !pluginDisabled; }
[MenuItem(dir + "Shortcuts", false, 101)] static void dadsas() { }
[MenuItem(dir + "Shortcuts", true, 101)] static bool dadsas123() => false;
[MenuItem(toggleActive, false, 102)] static void dadsadadsas() => toggleActiveEnabled = !toggleActiveEnabled;
[MenuItem(toggleActive, true, 102)] static bool dadsaddasadsas() { Menu.SetChecked(toggleActive, toggleActiveEnabled); return !pluginDisabled; }
[MenuItem(focus, false, 103)] static void dadsadasdadsas() => focusEnabled = !focusEnabled;
[MenuItem(focus, true, 103)] static bool dadsadsaddasadsas() { Menu.SetChecked(focus, focusEnabled); return !pluginDisabled; }
[MenuItem(delete, false, 104)] static void dadsadsadasdadsas() => deleteEnabled = !deleteEnabled;
[MenuItem(delete, true, 104)] static bool dadsaddsasaddasadsas() { Menu.SetChecked(delete, deleteEnabled); return !pluginDisabled; }
[MenuItem(toggleExpanded, false, 105)] static void dadsadsadasdsadadsas() => toggleExpandedEnabled = !toggleExpandedEnabled;
[MenuItem(toggleExpanded, true, 105)] static bool dadsaddsasadadsdasadsas() { Menu.SetChecked(toggleExpanded, toggleExpandedEnabled); return !pluginDisabled; }
[MenuItem(collapseEverythingElse, false, 106)] static void dadsadsasdadasdsadadsas() => collapseEverythingElseEnabled = !collapseEverythingElseEnabled;
[MenuItem(collapseEverythingElse, true, 106)] static bool dadsaddsdasasadadsdasadsas() { Menu.SetChecked(collapseEverythingElse, collapseEverythingElseEnabled); return !pluginDisabled; }
[MenuItem(collapseEverything, false, 107)] static void dadsadsdasadasdsadadsas() => collapseEverythingEnabled = !collapseEverythingEnabled;
[MenuItem(collapseEverything, true, 107)] static bool dadsaddssdaasadadsdasadsas() { Menu.SetChecked(collapseEverything, collapseEverythingEnabled); return !pluginDisabled; }
[MenuItem(dir + "More", false, 1001)] static void daasadsddsas() { }
[MenuItem(dir + "More", true, 1001)] static bool dadsadsdasas123() => false;
[MenuItem(dir + "Open manual", false, 1002)]
static void dadadsasdsadsas() => AssetDatabase.OpenAsset(AssetDatabase.LoadAssetAtPath<Object>(GetScriptPath("VHierarchy").GetParentPath().CombinePath("Manual.pdf")));
[MenuItem(dir + "Join our Discord", false, 1003)]
static void dadasdsas() => Application.OpenURL("https://discord.gg/4dG9KsbspG");
[MenuItem(dir + "Deals ending soon/Get vFolders 2 at 50% off", false, 1004)]
static void dadadssadasdsas() => Application.OpenURL("https://assetstore.unity.com/packages/slug/255470?aid=1100lGLBn&pubref=deal50menu");
[MenuItem(dir + "Deals ending soon/Get vInspector 2 at 50% off", false, 1005)]
static void dadadssadsas() => Application.OpenURL("https://assetstore.unity.com/packages/slug/252297?aid=1100lGLBn&pubref=deal50menu");
[MenuItem(dir + "Deals ending soon/Get vTabs 2 at 50% off", false, 1006)]
static void dadadadsssadsas() => Application.OpenURL("https://assetstore.unity.com/packages/slug/263645?aid=1100lGLBn&pubref=deal50menu");
[MenuItem(dir + "Deals ending soon/Get vFavorites 2 at 50% off", false, 1007)]
static void dadadadsssadsadsas() => Application.OpenURL("https://assetstore.unity.com/packages/slug/263643?aid=1100lGLBn&pubref=deal50menu");
[MenuItem(disablePlugin, false, 10001)] static void dadsadsdasadasdasdsadadsas() { pluginDisabled = !pluginDisabled; UnityEditor.Compilation.CompilationPipeline.RequestScriptCompilation(); }
[MenuItem(disablePlugin, true, 10001)] static bool dadsaddssdaasadsadadsdasadsas() { Menu.SetChecked(disablePlugin, pluginDisabled); return true; }
// [MenuItem(dir + "Clear cache", false, 10001)]
// static void dassaadsdc() => VHierarchyCache.Clear();
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4d7f0448bdeda4aad9cfdd9e7c7ee27f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,6 @@
// this file was present in a previus version and is supposed to be deleted now
// but asset store update delivery system doesn't allow deleting files
// so instead this file is now emptied
// feel free to delete it if you want

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9ddf1decb62f94768bcaec3173017c87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,217 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using UnityEditorInternal;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
public class VHierarchyPalette : ScriptableObject
{
public List<Color> colors = new List<Color>();
public bool colorsEnabled;
public void ResetColors()
{
colors.Clear();
for (int i = 0; i < colorsCount; i++)
colors.Add(GetDefaultColor(i));
colorsEnabled = true;
this.Dirty();
}
public static Color GetDefaultColor(int colorIndex)
{
Color color = default;
void grey()
{
if (colorIndex >= greyColorsCount) return;
#if UNITY_2022_1_OR_NEWER
color = Greyscale(isDarkTheme ? .16f : .9f);
#else
color = Greyscale(isDarkTheme ? .315f : .9f);
#endif
}
void rainbowDarkTheme()
{
if (colorIndex < greyColorsCount) return;
if (!isDarkTheme) return;
color = HSLToRGB((colorIndex - greyColorsCount.ToFloat()) / rainbowColorsCount, .45f, .35f);
if (colorIndex == 1)
color *= 1.2f;
if (colorIndex == 2)
color *= 1.1f;
if (colorIndex == 6)
color *= 1.35f;
if (colorIndex == 7)
color *= 1.3f;
if (colorIndex == 8)
color *= 1.05f;
color.a = .1f;
}
void rainbowLightTheme()
{
if (colorIndex < greyColorsCount) return;
if (isDarkTheme) return;
color = HSLToRGB((colorIndex - greyColorsCount.ToFloat()) / rainbowColorsCount, .62f, .8f);
color.a = .1f;
}
grey();
rainbowDarkTheme();
rainbowLightTheme();
return color;
}
public static int greyColorsCount = 1;
public static int rainbowColorsCount = 8;
public static int colorsCount => greyColorsCount + rainbowColorsCount;
public List<IconRow> iconRows = new List<IconRow>();
[System.Serializable]
public class IconRow
{
public List<string> builtinIcons = new List<string>(); // names
public List<string> customIcons = new List<string>(); // guids
public bool enabled = true;
public bool isCustom => !builtinIcons.Any() || customIcons.Any();
public bool isEmpty => !builtinIcons.Any() && !customIcons.Any();
public int iconCount => builtinIcons.Count + customIcons.Count;
public IconRow(string[] builtinIcons) => this.builtinIcons = builtinIcons.ToList();
public IconRow() { }
}
public void ResetIcons()
{
iconRows.Clear();
iconRows.Add(new IconRow(new[]
{
"Folder Icon",
"Canvas Icon",
"AvatarMask On Icon",
"cs Script Icon",
"StandaloneInputModule Icon",
"EventSystem Icon",
"Terrain Icon",
"ScriptableObject Icon",
}));
iconRows.Add(new IconRow(new[]
{
"Camera Icon",
"ParticleSystem Icon",
"TrailRenderer Icon",
"Material Icon",
"ReflectionProbe Icon",
}));
iconRows.Add(new IconRow(new[]
{
"Light Icon",
"DirectionalLight Icon",
"LightmapParameters Icon",
"LightProbes Icon",
}));
iconRows.Add(new IconRow(new[]
{
"Rigidbody Icon",
"BoxCollider Icon",
"SphereCollider Icon",
"CapsuleCollider Icon",
"WheelCollider Icon",
"MeshCollider Icon",
}));
iconRows.Add(new IconRow(new[]
{
"AudioSource Icon",
"AudioClip Icon",
"AudioListener Icon",
"AudioEchoFilter Icon",
"AudioReverbZone Icon",
}));
iconRows.Add(new IconRow(new[]
{
"PreMatCube",
"PreMatSphere",
"PreMatCylinder",
"PreMatQuad",
"Favorite",
#if UNITY_2021_3_OR_NEWER
"Settings Icon",
#endif
}));
this.Dirty();
}
[ContextMenu("Export palette")]
public void Export()
{
var packagePath = EditorUtility.SaveFilePanel("Export vHierarchy Palette", "", this.GetPath().GetFilename(withExtension: false), "unitypackage");
var iconPaths = iconRows.SelectMany(r => r.customIcons).Select(r => r.ToPath()).Where(r => !r.IsNullOrEmpty());
AssetDatabase.ExportPackage(iconPaths.Append(this.GetPath()).ToArray(), packagePath);
EditorUtility.RevealInFinder(packagePath);
}
void Reset() { ResetColors(); ResetIcons(); }
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61290d425f1c94a8cbfb56f754ca6757
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,723 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEditorInternal;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
using static VHierarchy.VHierarchyPalette;
namespace VHierarchy
{
[CustomEditor(typeof(VHierarchyPalette))]
public class VHierarchyPaletteEditor : Editor
{
public override void OnInspectorGUI()
{
void colors()
{
var rowRect = ExpandWidthLabelRect(cellSize).SetX(rowsOffsetX).SetWidth(rowWidth);
void backgroundHovered()
{
if (!rowRect.IsHovered()) return;
if (pickingColor) return;
if (draggingRow) return;
rowRect.Draw(hoveredRowBackground);
}
void toggle()
{
var toggleRect = rowRect.SetWidth(16).MoveX(5);
var prevEnabled = palette.colorsEnabled;
var newEnabled = EditorGUI.Toggle(toggleRect, palette.colorsEnabled);
if (prevEnabled != newEnabled)
palette.RecordUndo();
palette.colorsEnabled = newEnabled;
if (prevEnabled != newEnabled)
palette.Dirty();
}
void crossIcon()
{
var crossIconRect = rowRect.SetX(rowsOffsetX + iconsOffsetX + iconSpacing / 2).SetWidth(iconSize).SetHeightFromMid(iconSize);
SetGUIColor(palette.colorsEnabled ? Color.white : disabledRowTint);
SetLabelAlignmentCenter();
GUI.Label(crossIconRect, EditorGUIUtility.IconContent("CrossIcon"));
ResetGUIColor();
ResetLabelStyle();
}
void color(int i)
{
var cellRect = rowRect.MoveX(iconsOffsetX + (i + 1) * cellSize).SetWidth(cellSize).SetHeightFromMid(cellSize);
void backgroundPicking()
{
if (!pickingColor) return;
if (i != pickingColorAtIndex) return;
cellRect.DrawWithRoundedCorners(pickingBackground, 2);
}
void color()
{
var tint = palette.colorsEnabled ? Color.white : disabledRowTint;
var brightness = i < VHierarchyPalette.greyColorsCount ? 1.02f : 1.35f;
var outlineColor = i < VHierarchyPalette.greyColorsCount ? Greyscale(.0f, .4f) : Greyscale(.15f, .2f);
cellRect.Resize(3).DrawWithRoundedCorners(outlineColor * tint, 4);
cellRect.Resize(4).DrawWithRoundedCorners(palette.colors[i].SetAlpha(1) * brightness * tint, 3);
cellRect.Resize(4).AddWidthFromRight(-2).DrawCurtainLeft(GUIColors.windowBackground.SetAlpha((1 - palette.colors[i].a) * .5f));
}
void startPickingColorButton()
{
if (!palette.colorsEnabled) return;
if (!cellRect.IsHovered()) return;
if (pickingColor) return;
var clicked = GUI.Button(cellRect.Resize(1), "");
GUI.Label(cellRect.Resize(.5f), EditorGUIUtility.IconContent("Preset.Context"));
if (!clicked) return;
colorPicker = OpenColorPicker((c) => { palette.RecordUndo(); palette.Dirty(); palette.colors[i] = c; }, palette.colors[i], true, false);
colorPicker.MoveTo(EditorGUIUtility.GUIToScreenPoint(cellRect.Move(-3, 50).position));
pickingColor = true;
pickingColorAtIndex = i;
}
void updatePickingColor()
{
if (!pickingColor) return;
EditorApplication.RepaintHierarchyWindow();
}
void stopPickingColor()
{
if (!pickingColor) return;
if (colorPicker) return;
pickingColor = false;
}
cellRect.MarkInteractive();
backgroundPicking();
color();
startPickingColorButton();
updatePickingColor();
stopPickingColor();
}
backgroundHovered();
toggle();
crossIcon();
for (int i = 0; i < palette.colors.Count; i++)
color(i);
Space(rowSpacing - 2);
}
void icons()
{
void row(Rect rowRect, IconRow row)
{
var isLastRow = row == palette.iconRows.Last();
var isDraggedRow = row == draggedRow;
var spaceForCrossIcon = 0f;
void startPickingIcon(int i, Rect cellRect)
{
iconPicker = OpenObjectPicker<Texture2D>(AssetDatabase.LoadAssetAtPath<Texture2D>(row.customIcons[i].ToPath()), controlID: 123);
iconPicker.MoveTo(EditorGUIUtility.GUIToScreenPoint(cellRect.Move(-3, 50).position));
pickingIcon = true;
pickingIconAtIndex = i;
pickingIconAtRow = row;
}
void updatePickingIcon()
{
if (!pickingIcon) return;
if (pickingIconAtRow != row) return;
if (EditorGUIUtility.GetObjectPickerControlID() != 123) return;
if (pickingIconAtIndex >= row.customIcons.Count) return; // somehow happens if RecordUndo is used
palette.RecordUndo();
palette.Dirty();
row.customIcons[pickingIconAtIndex] = (EditorGUIUtility.GetObjectPickerObject() as Texture2D).GetPath().ToGuid();
}
void stopPickingIcon()
{
if (!pickingIcon) return;
if (pickingIconAtRow != row) return;
if (iconPicker) return;
if (pickingIconAtIndex < row.customIcons.Count)
if (row.customIcons[pickingIconAtIndex] == null)
row.customIcons.RemoveAt(pickingIconAtIndex);
pickingIcon = false;
}
void dragndrop()
{
if (!rowRect.IsHovered()) return;
if (curEvent.isDragUpdate && DragAndDrop.objectReferences.First() is Texture2D)
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (!curEvent.isDragPerform) return;
if (!(DragAndDrop.objectReferences.Any(r => r is Texture2D))) return;
DragAndDrop.AcceptDrag();
palette.RecordUndo();
palette.Dirty();
foreach (var icon in DragAndDrop.objectReferences.Where(r => r is Texture2D))
row.customIcons.Add(icon.GetPath().ToGuid());
}
void calcSpaceForCrossIcon()
{
if (row == curFirstEnabledRow)
spaceForCrossIcon = crossIconAnimationT * cellSize;
if (row == crossIconAnimationSourceRow)
spaceForCrossIcon = (1 - crossIconAnimationT) * cellSize;
}
void backgroundHovered()
{
if (!rowRect.IsHovered()) return;
if (pickingColor) return;
if (pickingIcon) return;
if (draggingRow) return;
rowRect.Draw(hoveredRowBackground);
}
void backgroundDragged()
{
if (!isDraggedRow) return;
rowRect.DrawBlurred(Greyscale(0, .3f), 12);
rowRect.Draw(draggedRowBackground);
}
void toggle()
{
var prevEnabled = row.enabled;
var newEnabled = EditorGUI.Toggle(rowRect.SetWidth(16).MoveX(5), row.enabled);
if (prevEnabled != newEnabled)
palette.RecordUndo();
row.enabled = newEnabled;
if (prevEnabled != newEnabled)
palette.Dirty();
}
void addIconButton()
{
if (!row.isCustom) return;
var cellRect = rowRect.MoveX(iconsOffsetX + row.customIcons.Count * cellSize + spaceForCrossIcon).SetWidth(cellSize).SetHeightFromMid(cellSize);
SetGUIColor(Greyscale(1, row.enabled ? 1 : .5f));
var clicked = GUI.Button(cellRect.Resize(1), "");
ResetGUIColor();
SetGUIColor(Greyscale(1, row.enabled ? 1 : .5f));
SetLabelAlignmentCenter();
GUI.Label(cellRect.Resize(1), EditorGUIUtility.IconContent("Toolbar Plus"));
ResetLabelStyle();
ResetGUIColor();
if (!clicked) return;
palette.RecordUndo();
row.customIcons.Add(null);
startPickingIcon(row.customIcons.Count - 1, cellRect);
}
void icon(int i)
{
var cellRect = rowRect.MoveX(iconsOffsetX + spaceForCrossIcon + i * cellSize).SetWidth(cellSize).SetHeightFromMid(cellSize);
var isCustomIcon = i > row.builtinIcons.Count - 1;
void backgroundPicking()
{
if (!pickingIcon) return;
if (row != pickingIconAtRow) return;
if (i != pickingIconAtIndex) return;
cellRect.Resize(1).DrawWithRoundedCorners(pickingBackground, 2);
}
void drawBuiltin()
{
if (isCustomIcon) return;
SetLabelAlignmentCenter();
SetGUIColor(row.enabled ? Color.white : disabledRowTint);
GUI.Label(cellRect.SetSizeFromMid(iconSize), EditorGUIUtility.IconContent(row.builtinIcons[i]));
ResetLabelStyle();
ResetGUIColor();
}
void drawCustom()
{
if (!isCustomIcon) return;
if (cellRect.IsHovered()) return;
if (!(AssetDatabase.LoadAssetAtPath<Texture2D>(row.customIcons[i - row.builtinIcons.Count].ToPath()) is Texture2D texture)) return;
SetGUIColor(row.enabled ? Color.white : disabledRowTint);
GUI.DrawTexture(cellRect.SetSizeFromMid(iconSize), texture);
ResetGUIColor();
}
void editCustomButton()
{
if (!isCustomIcon) return;
if (!cellRect.IsHovered()) return;
if (pickingIcon) return;
var clicked = GUI.Button(cellRect.Resize(1), "");
GUI.Label(cellRect.Resize(.5f), EditorGUIUtility.IconContent("Preset.Context"));
if (!clicked) return;
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Replace icon"), false, () => { palette.RecordUndo(); palette.Dirty(); startPickingIcon(i, cellRect.MoveY(75)); });
menu.AddItem(new GUIContent("Remove icon"), false, () => { palette.RecordUndo(); row.customIcons.RemoveAt(i); palette.Dirty(); });
menu.ShowAsContext();
}
cellRect.MarkInteractive();
backgroundPicking();
drawBuiltin();
drawCustom();
editCustomButton();
}
rowRect.MarkInteractive();
updatePickingIcon();
stopPickingIcon();
dragndrop();
calcSpaceForCrossIcon();
backgroundHovered();
backgroundDragged();
toggle();
addIconButton();
for (int i = 0; i < row.iconCount; i++)
icon(i);
}
void updateRowsCount()
{
palette.iconRows.RemoveAll(r => r.isEmpty && r != palette.iconRows.Last());
if (!palette.iconRows.Last().isEmpty)
palette.iconRows.Add(new IconRow());
}
void updateRowGapsCount()
{
while (rowGaps.Count < palette.iconRows.Count)
rowGaps.Add(0);
while (rowGaps.Count > palette.iconRows.Count)
rowGaps.RemoveLast();
}
void normalRow(int i)
{
Space(rowGaps[i] * (cellSize + rowSpacing));
if (i == 0 && lastRect.y != 0)
firstRowY = lastRect.y;
Space(cellSize + rowSpacing);
var rowRect = Rect.zero.SetPos(rowsOffsetX, lastRect.y).SetSize(rowWidth, cellSize);
if (curEvent.isRepaint)
if (rowRect.IsHovered())
hoveredRow = palette.iconRows[i];
row(rowRect, palette.iconRows[i]);
}
void draggedRow_()
{
if (!draggingRow) return;
draggedRowY = (curEvent.mousePosition.y + draggedRowHoldOffset).Clamp(firstRowY, firstRowY + (palette.iconRows.Count - 1) * (cellSize + rowSpacing));
var rowRect = Rect.zero.SetPos(rowsOffsetX, draggedRowY).SetSize(rowWidth, cellSize);
row(rowRect, draggedRow);
}
void crossIcon()
{
if (!palette.iconRows.Any(r => r.enabled)) return;
var rect = Rect.zero.SetPos(rowsOffsetX + iconsOffsetX, crossIconY).SetSize(cellSize, cellSize).Resize(iconSpacing / 2);
SetLabelAlignmentCenter();
GUI.Label(rect, EditorGUIUtility.IconContent("CrossIcon"));
ResetLabelStyle();
}
updateRowsCount();
updateRowGapsCount();
if (curEvent.isRepaint)
hoveredRow = null;
for (int i = 0; i < palette.iconRows.Count; i++)
normalRow(i);
crossIcon();
draggedRow_();
}
void tutor()
{
SetGUIEnabled(false);
GUILayout.Label("Click a color to edit it");
Space(4);
GUILayout.Label("Click '+' to add a custom icon");
Space(4);
GUILayout.Label("Click a custom icon to replace or remove it");
Space(4);
GUILayout.Label("Drag rows to reorder them");
ResetGUIEnabled();
}
Space(15);
colors();
Space(15);
icons();
Space(25);
tutor();
UpdateAnimations();
UpdateDragging();
palette.Dirty();
if (draggingRow || animatingCrossIcon)
Repaint();
}
float iconSize => 18;
float iconSpacing => 2;
float cellSize => iconSize + iconSpacing;
float rowSpacing = 1;
float rowsOffsetX => 14;
float iconsOffsetX => 27;
Color hoveredRowBackground => Greyscale(isDarkTheme ? 1 : 0, .05f);
Color draggedRowBackground => Greyscale(isDarkTheme ? .3f : .9f);
Color pickingBackground => Greyscale(1, .17f);
Color disabledRowTint => Greyscale(1, .45f);
float rowWidth => cellSize * Mathf.Max(palette.colors.Count, palette.iconRows.Max(r => r.iconCount + 1)) + 55;
bool pickingColor;
int pickingColorAtIndex;
EditorWindow colorPicker;
bool pickingIcon;
int pickingIconAtIndex;
IconRow pickingIconAtRow;
EditorWindow iconPicker;
IconRow hoveredRow;
float firstRowY = 51;
void UpdateAnimations()
{
void calcDeltaTime()
{
if (!curEvent.isLayout) return;
deltaTime = (float)(EditorApplication.timeSinceStartup - lastLayoutTime);
if (deltaTime > .05f)
deltaTime = .0166f;
lastLayoutTime = EditorApplication.timeSinceStartup;
}
void lerpRowGaps()
{
if (!curEvent.isLayout) return;
var lerpSpeed = draggingRow ? 12 : 12321;
for (int i = 0; i < rowGaps.Count; i++)
rowGaps[i] = Lerp(rowGaps[i], draggingRow && i == insertDraggedRowAtIndex ? 1 : 0, lerpSpeed, deltaTime);// todo deltatime
for (int i = 0; i < rowGaps.Count; i++)
if (rowGaps[i].Approx(0))
rowGaps[i] = 0;
else if (rowGaps[i].Approx(1))
rowGaps[i] = 1;
}
void lerpCrossIconAnimationT()
{
if (!curEvent.isLayout) return;
var lerpSpeed = 12;
Lerp(ref crossIconAnimationT, 1, lerpSpeed, deltaTime);
}
void startCrossIconAnimation()
{
if (prevFirstEnabledRow == null) { prevFirstEnabledRow = curFirstEnabledRow; return; }
if (prevFirstEnabledRow == curFirstEnabledRow) return;
crossIconAnimationT = 0;
crossIconAnimationSourceRow = prevFirstEnabledRow;
prevFirstEnabledRow = curFirstEnabledRow;
}
void stopCrossIconAnimation()
{
if (!crossIconAnimationT.Approx(1)) return;
crossIconAnimationT = 1;
crossIconAnimationSourceRow = null;
}
void calcCrossIconY()
{
var indexOfFirstEnabled = palette.iconRows.IndexOfFirst(r => r.enabled);
var yOfFirstEnabled = firstRowY + indexOfFirstEnabled * (cellSize + rowSpacing);
for (int i = 0; i < indexOfFirstEnabled + 1; i++)
yOfFirstEnabled += rowGaps[i] * (cellSize + rowSpacing);
var indexOfSourceRow = palette.iconRows.IndexOf(crossIconAnimationSourceRow);
var yOfSourceRow = firstRowY + indexOfSourceRow * (cellSize + rowSpacing);
for (int i = 0; i < indexOfSourceRow + 1; i++)
yOfSourceRow += rowGaps[i] * (cellSize + rowSpacing);
if (crossIconAnimationSourceRow == draggedRow)
yOfSourceRow = draggedRowY;
crossIconY = Lerp(yOfSourceRow, yOfFirstEnabled, crossIconAnimationT);
if (indexOfFirstEnabled == indexOfSourceRow) { crossIconAnimationT = 1; }
}
calcDeltaTime();
lerpRowGaps();
lerpCrossIconAnimationT();
startCrossIconAnimation();
stopCrossIconAnimation();
calcCrossIconY();
}
List<float> rowGaps = new List<float>();
float deltaTime;
double lastLayoutTime;
float crossIconY = 51;
float crossIconAnimationT = 1;
IconRow crossIconAnimationSourceRow;
bool animatingCrossIcon => crossIconAnimationT != 1;
IconRow prevFirstEnabledRow;
IconRow curFirstEnabledRow => palette.iconRows.FirstOrDefault(r => r.enabled);
void UpdateDragging()
{
void startDragging()
{
if (draggingRow) return;
if (!curEvent.isMouseDrag) return;
if (hoveredRow == null) return;
if (hoveredRow == palette.iconRows.Last()) return;
palette.RecordUndo();
draggingRow = true;
draggedRow = hoveredRow;
draggingRowFromIndex = palette.iconRows.IndexOf(hoveredRow);
draggedRowHoldOffset = firstRowY + draggingRowFromIndex * (cellSize + rowSpacing) - curEvent.mousePosition.y;
palette.iconRows.Remove(hoveredRow);
rowGaps[draggingRowFromIndex] = 1;
}
void updateDragging()
{
if (!draggingRow) return;
insertDraggedRowAtIndex = ((curEvent.mousePosition.y - firstRowY) / (cellSize + rowSpacing)).FloorToInt().Clamp(0, palette.iconRows.Count - 1);
EditorGUIUtility.hotControl = EditorGUIUtility.GetControlID(FocusType.Passive);
}
void stopDragging()
{
if (!draggingRow) return;
if (!curEvent.isMouseUp) return;
palette.RecordUndo();
palette.Dirty();
palette.iconRows.AddAt(draggedRow, insertDraggedRowAtIndex);
rowGaps[insertDraggedRowAtIndex] = 0;
draggingRow = false;
draggedRow = null;
EditorGUIUtility.hotControl = 0;
}
startDragging();
updateDragging();
stopDragging();
}
IconRow draggedRow;
bool draggingRow;
int draggingRowFromIndex;
float draggedRowHoldOffset;
float draggedRowY;
int insertDraggedRowAtIndex;
VHierarchyPalette palette => target as VHierarchyPalette;
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2b7dce55e9e9b476fb5d1d669c006123
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,550 @@
#if UNITY_EDITOR
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using System.Reflection;
using System.Linq;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
using Type = System.Type;
using static VHierarchy.VHierarchyData;
using static VHierarchy.VHierarchyPalette;
using static VHierarchy.Libs.VUtils;
using static VHierarchy.Libs.VGUI;
namespace VHierarchy
{
public class VHierarchyPaletteWindow : EditorWindow
{
void OnGUI()
{
if (!palette) { Close(); return; }
int hoveredColorIndex = -1;
string hoveredIconNameOrGuid = null;
void background()
{
position.SetPos(0, 0).Draw(windowBackground);
}
void outline()
{
if (Application.platform == RuntimePlatform.OSXEditor) return;
position.SetPos(0, 0).DrawOutline(Greyscale(.1f));
}
void colors()
{
if (!palette.colorsEnabled) { Space(-spaceAfterColors); return; }
var rowRect = ExpandWidthLabelRect(height: cellSize).SetX(paddingX);
void color(int i)
{
var cellRect = rowRect.MoveX(i * cellSize).SetWidth(cellSize).SetHeightFromMid(cellSize);
void backgroundSelected()
{
if (!initialColorIndexes.Contains(i)) return;
cellRect.Resize(1).DrawWithRoundedCorners(selectedBackground, 2);
}
void backgroundHovered()
{
if (!cellRect.IsHovered()) return;
cellRect.Resize(1).DrawWithRoundedCorners(this.hoveredBackground, 2);
}
void crossIcon()
{
if (i != 0) return;
SetLabelAlignmentCenter();
GUI.Label(cellRect.SetSizeFromMid(iconSize), EditorGUIUtility.IconContent("CrossIcon"));
ResetLabelStyle();
}
void color()
{
if (i == 0) return;
var brightness = i <= VHierarchyPalette.greyColorsCount ? 1.02f : 1.35f;
var outlineColor = i <= VHierarchyPalette.greyColorsCount ? Greyscale(.0f, .4f) : Greyscale(.15f, .2f);
cellRect.Resize(3).DrawWithRoundedCorners(outlineColor, 4);
cellRect.Resize(4).DrawWithRoundedCorners((palette.colors[i - 1] * brightness).SetAlpha(1), 3);
cellRect.Resize(4).AddWidthFromRight(-2).DrawCurtainLeft(GUIColors.windowBackground.SetAlpha((1 - palette.colors[i - 1].a) * .45f));
}
void setHovered()
{
if (!cellRect.IsHovered()) return;
hoveredColorIndex = i;
}
void closeOnClick()
{
if (!cellRect.IsHovered()) return;
if (!curEvent.isMouseDown) return;
Close();
}
cellRect.MarkInteractive();
backgroundSelected();
backgroundHovered();
crossIcon();
color();
setHovered();
closeOnClick();
}
for (int i = 0; i < palette.colors.Count + 1; i++)
color(i);
}
void icons()
{
void row(IconRow iconRow)
{
if (!iconRow.enabled) return;
if (iconRow.isEmpty) return;
var rowRect = ExpandWidthLabelRect(height: cellSize).SetX(paddingX);
var isFirstEnabledRow = palette.iconRows.First(r => r.enabled) == iconRow;
void icon(int i)
{
var cellRect = rowRect.MoveX(i * cellSize).SetWidth(cellSize).SetHeightFromMid(cellSize);
var isCrossIcon = isFirstEnabledRow && i == 0;
var actualIconIndex = isFirstEnabledRow ? i - 1 : i;
var isBuiltinIcon = !isCrossIcon && actualIconIndex < iconRow.builtinIcons.Count;
var isCustomIcon = !isCrossIcon && actualIconIndex >= iconRow.builtinIcons.Count;
var iconNameOrGuid = isCrossIcon ? "" : isCustomIcon ? iconRow.customIcons[actualIconIndex - iconRow.builtinIcons.Count] : iconRow.builtinIcons[actualIconIndex];
void backgroundSelected()
{
if (!initialIconNamesOrGuids.Contains(iconNameOrGuid)) return;
cellRect.Resize(1).DrawWithRoundedCorners(selectedBackground, 2);
}
void backgroundHovered()
{
if (!cellRect.IsHovered()) return;
cellRect.Resize(1).DrawWithRoundedCorners(this.hoveredBackground, 2);
}
void crossIcon()
{
if (!isCrossIcon) return;
SetLabelAlignmentCenter();
GUI.Label(cellRect.SetSizeFromMid(iconSize), EditorGUIUtility.IconContent("CrossIcon"));
ResetLabelStyle();
}
void builtinIcon()
{
if (!isBuiltinIcon) return;
SetLabelAlignmentCenter();
GUI.Label(cellRect.SetSizeFromMid(iconSize), EditorGUIUtility.IconContent(iconNameOrGuid));
ResetLabelStyle();
}
void customIcon()
{
if (!isCustomIcon) return;
var texture = AssetDatabase.LoadAssetAtPath<Texture2D>(iconNameOrGuid.ToPath());
GUI.DrawTexture(cellRect.SetSizeFromMid(iconSize), texture ?? Texture2D.blackTexture);
}
void setHovered()
{
if (!cellRect.IsHovered()) return;
hoveredIconNameOrGuid = iconNameOrGuid;
}
void closeOnClick()
{
if (!cellRect.IsHovered()) return;
if (!curEvent.isMouseDown) return;
Close();
}
cellRect.MarkInteractive();
backgroundSelected();
backgroundHovered();
crossIcon();
builtinIcon();
customIcon();
setHovered();
closeOnClick();
}
for (int i = 0; i < iconRow.iconCount + (isFirstEnabledRow ? 1 : 0); i++)
icon(i);
Space(rowSpacing - 2);
}
for (int i = 0; i < palette.iconRows.Count; i++)
row(palette.iconRows[i]);
}
void setColorsAndIcons()
{
if (!curEvent.isRepaint) return;
if (palette.iconRows.Any(r => r.enabled))
if (hoveredIconNameOrGuid != null)
SetIcon(hoveredIconNameOrGuid);
else
SetInitialIcons();
if (palette.colorsEnabled)
if (hoveredColorIndex != -1)
SetColor(hoveredColorIndex);
else
SetInitialColors();
}
void updatePosition()
{
if (!curEvent.isLayout) return;
void calcDeltaTime()
{
deltaTime = (float)(EditorApplication.timeSinceStartup - lastLayoutTime);
if (deltaTime > .05f)
deltaTime = .0166f;
lastLayoutTime = EditorApplication.timeSinceStartup;
}
void resetCurPos()
{
if (currentPosition != default) return;
currentPosition = position.position; // position.position is always int, which can't be used for lerping
}
void lerpCurPos()
{
var speed = 9;
SmoothDamp(ref currentPosition, targetPosition, speed, ref positionDeriv, deltaTime);
// Lerp(ref currentPosition, targetPosition, speed, deltaTime);
}
void setCurPos()
{
position = position.SetPos(currentPosition);
}
calcDeltaTime();
resetCurPos();
lerpCurPos();
setCurPos();
if (!currentPosition.y.Approx(targetPosition.y))
Repaint();
}
void closeOnEscape()
{
if (!curEvent.isKeyDown) return;
if (curEvent.keyCode != KeyCode.Escape) return;
SetInitialColors();
SetInitialIcons();
Close();
}
RecordUndoOnDatas();
background();
outline();
Space(paddingY);
colors();
Space(spaceAfterColors);
icons();
setColorsAndIcons();
updatePosition();
closeOnEscape();
EditorApplication.RepaintHierarchyWindow();
}
static float iconSize => 18;
static float iconSpacing => 2;
static float cellSize => iconSize + iconSpacing;
static float spaceAfterColors => 11;
public float rowSpacing = 1;
static float paddingX => 12;
static float paddingY => 12;
Color windowBackground => isDarkTheme ? Greyscale(.23f) : Greyscale(.7f);
Color selectedBackground => isDarkTheme ? new Color(.3f, .5f, .7f, .8f) : new Color(.3f, .5f, .7f, .4f) * 1.35f;
Color hoveredBackground = Greyscale(1, .3f);
public Vector2 targetPosition;
public Vector2 currentPosition;
Vector2 positionDeriv;
float deltaTime;
double lastLayoutTime;
void SetIcon(string iconNameOrGuid)
{
foreach (var r in goDatas)
r.iconNameOrGuid = iconNameOrGuid;
}
void SetColor(int colorIndex)
{
foreach (var r in goDatas)
r.colorIndex = colorIndex;
}
void SetInitialIcons()
{
for (int i = 0; i < goDatas.Count; i++)
goDatas[i].iconNameOrGuid = initialIconNamesOrGuids[i];
}
void SetInitialColors()
{
for (int i = 0; i < goDatas.Count; i++)
goDatas[i].colorIndex = initialColorIndexes[i];
}
void RemoveEmptyGoDatas()
{
var toRemove = goDatas.Where(r => r.iconNameOrGuid == "" && r.colorIndex == 0);
foreach (var goData in toRemove)
goData.sceneData.goDatas_byGlobalId.RemoveValue(goData);
if (toRemove.Any())
Undo.CollapseUndoOperations(Undo.GetCurrentGroup() - 1);
}
void RecordUndoOnDatas()
{
if (usingDataSO)
if (data)
data.RecordUndo();
foreach (var r in usedDataComponents)
r.RecordUndo();
}
void MarkDatasDirty()
{
if (usingDataSO)
if (data)
data.Dirty();
foreach (var r in usedDataComponents)
r.Dirty();
}
void SaveData()
{
if (usingDataSO)
data.Save();
}
bool usingDataSO => !gameObjects.Select(r => r.scene).All(r => VHierarchy.dataComponents_byScene.GetValueOrDefault(r) != null);
IEnumerable<VHierarchyDataComponent> usedDataComponents => VHierarchy.dataComponents_byScene.Where(kvp => kvp.Value && gameObjects.Select(r => r.scene).Contains(kvp.Key)).Select(kvp => kvp.Value);
void OnLostFocus()
{
if (curEvent.holdingAlt && EditorWindow.focusedWindow?.GetType().Name == "SceneHierarchyWindow")
CloseNextFrameIfNotRefocused();
else
Close();
}
void CloseNextFrameIfNotRefocused()
{
EditorApplication.delayCall += () => { if (EditorWindow.focusedWindow != this) Close(); };
}
public void Init(List<GameObject> gameObjects)
{
void createData()
{
if (VHierarchy.data) return;
VHierarchy.data = ScriptableObject.CreateInstance<VHierarchyData>();
AssetDatabase.CreateAsset(VHierarchy.data, GetScriptPath("VHierarchy").GetParentPath().CombinePath("vHierarchy Data.asset"));
}
void createPalette()
{
if (VHierarchy.palette) return;
VHierarchy.palette = ScriptableObject.CreateInstance<VHierarchyPalette>();
AssetDatabase.CreateAsset(VHierarchy.palette, GetScriptPath("VHierarchy").GetParentPath().CombinePath("vHierarchy Palette.asset"));
}
void setSize()
{
var rowCellCounts = new List<int>();
if (palette.colorsEnabled)
rowCellCounts.Add(palette.colors.Count + 1);
foreach (var r in palette.iconRows.Where(r => r.enabled))
rowCellCounts.Add(r.iconCount + (r == palette.iconRows.First(r => r.enabled) ? 1 : 0));
var width = rowCellCounts.Max() * cellSize + paddingX * 2;
var iconRowCount = palette.iconRows.Count(r => r.enabled && !r.isEmpty);
var rowCount = iconRowCount + (palette.colorsEnabled ? 1 : 0);
var height = rowCount * (cellSize + rowSpacing) + (palette.colorsEnabled && palette.iconRows.Any(r => r.enabled && !r.isEmpty) ? spaceAfterColors : 0) + paddingY * 2;
position = position.SetSize(width, height).SetPos(targetPosition);
}
void getDatas()
{
goDatas.Clear();
foreach (var r in gameObjects)
goDatas.Add(VHierarchy.GetGameObjectData(r, createDataIfDoesntExist: true));
}
void getInitColorsAndIcons()
{
initialColorIndexes.Clear();
initialIconNamesOrGuids.Clear();
foreach (var r in goDatas)
initialColorIndexes.Add(r.colorIndex);
foreach (var r in goDatas)
initialIconNamesOrGuids.Add(r.iconNameOrGuid);
}
this.gameObjects = gameObjects;
RecordUndoOnDatas();
createData();
createPalette();
setSize();
getDatas();
getInitColorsAndIcons();
}
void OnDestroy()
{
RemoveEmptyGoDatas();
MarkDatasDirty();
SaveData();
}
public List<GameObject> gameObjects = new List<GameObject>();
public List<GameObjectData> goDatas = new List<GameObjectData>();
public List<int> initialColorIndexes = new List<int>();
public List<string> initialIconNamesOrGuids = new List<string>();
static VHierarchyPalette palette => VHierarchy.palette;
static VHierarchyData data => VHierarchy.data;
public static void CreateInstance(Vector2 position)
{
instance = ScriptableObject.CreateInstance<VHierarchyPaletteWindow>();
instance.ShowPopup();
instance.position = instance.position.SetPos(position).SetSize(200, 300);
instance.targetPosition = position;
}
public static VHierarchyPaletteWindow instance;
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8ae240588f29744208e627125db9c9e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,21 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3a9752b0c8e144801967e6897679604b, type: 3}
m_Name: vHierarchy Data
m_EditorClassIdentifier:
sceneDatas_byGuid:
keys:
- 99c9720ab356a0642a771bea13969a05
values:
- goDatas_byGlobalId:
keys: []
values: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 258a078a981a33b4cb3d28d7518292dd
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,78 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 61290d425f1c94a8cbfb56f754ca6757, type: 3}
m_Name: vHierarchy Palette
m_EditorClassIdentifier:
colors:
- {r: 0.16, g: 0.16, b: 0.16, a: 1}
- {r: 0.609, g: 0.231, b: 0.23100014, a: 0.1}
- {r: 0.55825, g: 0.471625, b: 0.21175, a: 0.1}
- {r: 0.34999996, g: 0.5075, b: 0.1925, a: 0.1}
- {r: 0.1925, g: 0.5075, b: 0.27124998, a: 0.1}
- {r: 0.1925, g: 0.50750005, b: 0.5075, a: 0.1}
- {r: 0.259875, g: 0.36618757, b: 0.685125, a: 0.1}
- {r: 0.4550001, g: 0.25024998, b: 0.65975, a: 0.1}
- {r: 0.53287494, g: 0.20212498, b: 0.4501876, a: 0.1}
colorsEnabled: 1
iconRows:
- builtinIcons:
- Folder Icon
- Canvas Icon
- AvatarMask On Icon
- cs Script Icon
- StandaloneInputModule Icon
- EventSystem Icon
- Terrain Icon
- ScriptableObject Icon
customIcons: []
enabled: 1
- builtinIcons:
- Camera Icon
- ParticleSystem Icon
- TrailRenderer Icon
- Material Icon
- ReflectionProbe Icon
customIcons: []
enabled: 1
- builtinIcons:
- Light Icon
- DirectionalLight Icon
- LightmapParameters Icon
- LightProbes Icon
customIcons: []
enabled: 1
- builtinIcons:
- Rigidbody Icon
- BoxCollider Icon
- SphereCollider Icon
- CapsuleCollider Icon
- WheelCollider Icon
- MeshCollider Icon
customIcons: []
enabled: 1
- builtinIcons:
- AudioSource Icon
- AudioClip Icon
- AudioListener Icon
- AudioEchoFilter Icon
- AudioReverbZone Icon
customIcons: []
enabled: 1
- builtinIcons:
- PreMatCube
- PreMatSphere
- PreMatCylinder
- PreMatQuad
- Favorite
- Settings Icon
customIcons: []
enabled: 1

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 150e54b62f1dc324586c8422a12aee4b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant: