Last active
March 2, 2024 12:43
-
-
Save jschieck/26d40404491523a9967fc9804068691d to your computer and use it in GitHub Desktop.
Show a flyout project window in the scene view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEditor; | |
using UnityEditor.Callbacks; | |
using UnityEditor.Compilation; | |
using UnityEngine; | |
public static class FlyoutProjectWindow | |
{ | |
private const double _animDuration = 0.25f; | |
private const float _sizeRatio = 0.4f; | |
private static Func<Event, bool> _triggerEvent = e => | |
{ | |
#if UNITY_EDITOR_WIN | |
return e.alt && e.keyCode == KeyCode.P; | |
#else | |
return e.control && e.shift && e.keyCode == KeyCode.P; | |
#endif | |
}; | |
private static Func<Event, SceneView, bool> _clickSceneView = (e, s) => | |
{ | |
return e.type == EventType.MouseUp && e.button == 0 && s.position.Contains(e.mousePosition); | |
}; | |
private static Type _projectBrowserType = System.Reflection.Assembly.GetAssembly(typeof(EditorWindow)).GetTypes().First(t => t.Name == "ProjectBrowser"); | |
private class WindowData | |
{ | |
public EditorWindow Browser; | |
public bool Showing; | |
public bool EventActive; | |
public double AnimStartTime; | |
public Rect Target; | |
public Rect StartSize; | |
} | |
[InitializeOnLoadMethod] | |
private static void Init() | |
{ | |
SceneView.duringSceneGui += OnSceneGUI; | |
CompilationPipeline.assemblyCompilationStarted += CloseAllWindows; | |
} | |
[DidReloadScripts] | |
private static void ScriptsCompiling() | |
{ | |
CloseAllWindows(null); | |
} | |
private static void CloseAllWindows(string _) | |
{ | |
foreach (var window in _windows) | |
if (window.Value.Browser != null) | |
window.Value.Browser.Close(); | |
_windows.Clear(); | |
} | |
private static Dictionary<SceneView, WindowData> _windows = new Dictionary<SceneView, WindowData>(); | |
private static void UpdateBrowserPosition(SceneView sceneView, WindowData data) | |
{ | |
if (data.Browser == null) | |
{ | |
_windows.Remove(sceneView); | |
return; | |
} | |
var lerp = (float)((EditorApplication.timeSinceStartup - data.AnimStartTime) / _animDuration); | |
if (lerp <= 0f) return; | |
if (lerp >= 1f) | |
{ | |
if (!data.Showing || sceneView == null) | |
{ | |
if (data.Browser != null) data.Browser.Close(); | |
_windows.Remove(sceneView); | |
return; | |
} | |
else | |
{ | |
var scene = sceneView.position; | |
scene.y += scene.height * (1f - _sizeRatio); | |
scene.height *= _sizeRatio; | |
data.Target = data.StartSize = scene; | |
data.Browser.position = scene; | |
data.Browser.Repaint(); | |
data.EventActive = false; | |
} | |
return; | |
} | |
data.Browser.Focus(); | |
var time = (float)(EditorApplication.timeSinceStartup - data.AnimStartTime); | |
var lerpValue = OutBackEase(time, (float)_animDuration); | |
data.Browser.position = new Rect(data.Target.x, Mathf.Lerp(data.StartSize.y, data.Target.y, lerpValue), data.Target.width, Mathf.Lerp(data.StartSize.height, data.Target.height, lerpValue)); | |
data.Browser.Repaint(); | |
SceneView.RepaintAll(); | |
} | |
private static float OutBackEase(float time, float duration, float overshoot = 0.25f) | |
{ | |
return ((time = time / duration - 1) * time * ((overshoot + 1) * time + overshoot) + 1); | |
} | |
private static bool ValidateBrowser(SceneView sceneView, EditorWindow browser) | |
{ | |
if (sceneView == null) | |
{ | |
_windows.Remove(sceneView); | |
if (browser != null) | |
{ | |
browser.Close(); | |
} | |
return false; | |
} | |
if (!_windows.ContainsKey(sceneView) && browser != null) | |
{ | |
browser.Close(); | |
return false; | |
} | |
if (browser == null) | |
return false; | |
return true; | |
} | |
private static void OnSceneGUI(SceneView sceneView) | |
{ | |
var e = Event.current; | |
WindowData data = null; | |
if (_windows.TryGetValue(sceneView, out data)) | |
{ | |
UpdateBrowserPosition(sceneView, data); | |
} | |
if (e == null) return; | |
if (_triggerEvent(e) || ((data?.Showing ?? false) && _clickSceneView(e, sceneView))) | |
{ | |
if (data?.EventActive ?? false) return; | |
data = GetProjectBrowser(sceneView); | |
data.EventActive = true; | |
data.AnimStartTime = EditorApplication.timeSinceStartup; | |
data.Showing = !data.Showing; | |
data.StartSize = data.Target; | |
data.Target = sceneView.position; | |
if (data.Showing) | |
{ | |
data.Target.y += data.Target.height * (1f - _sizeRatio); | |
data.Target.height *= _sizeRatio; | |
} | |
else | |
{ | |
data.Target.y += data.Target.height; | |
data.Target.height = 1; | |
} | |
e.Use(); | |
} | |
} | |
private static WindowData GetProjectBrowser(SceneView sceneView) | |
{ | |
try | |
{ | |
if (!_windows.TryGetValue(sceneView, out var data) || data.Browser == null) | |
{ | |
data = new WindowData(); | |
data.Browser = ScriptableObject.CreateInstance(_projectBrowserType) as EditorWindow; | |
var scenePosition = sceneView.position; | |
scenePosition.y += scenePosition.height; | |
scenePosition.height = 1f; | |
data.Target = scenePosition; | |
data.Browser.ShowPopup(); | |
data.Browser.position = data.Target; | |
data.Browser.Repaint(); | |
_windows.Remove(sceneView); | |
_windows.Add(sceneView, data); | |
Action<SceneView> validate = null; | |
validate = _ => | |
{ | |
if (!ValidateBrowser(sceneView, data.Browser)) | |
SceneView.beforeSceneGui -= validate; | |
}; | |
SceneView.beforeSceneGui += validate; | |
EditorApplication.CallbackFunction validateEditor = null; | |
validateEditor = () => | |
{ | |
if (!ValidateBrowser(sceneView, data.Browser)) | |
EditorApplication.update -= validateEditor; | |
}; | |
EditorApplication.update += validateEditor; | |
} | |
return data; | |
} | |
catch (Exception ex) | |
{ | |
Debug.LogException(ex); | |
} | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey! I know it maybe rude to comment here, I tried to send you email before get no response. Could you please fix some Error issue of your asset Mesh animator in unity asset store. It is a brilliant asset and I really like its function of snapshot animation, which is unique and powerful even compare to ECS animation. But it doesnt work properly now in new LTS version(Mine use 2022.3.LTS), which is very pity. I tried to fix it myself but cant find the clue, so do please fix it, it`s a very good asset.