Skip to content

Instantly share code, notes, and snippets.

@jschieck
Last active March 2, 2024 12:43
Show Gist options
  • Star 14 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jschieck/26d40404491523a9967fc9804068691d to your computer and use it in GitHub Desktop.
Save jschieck/26d40404491523a9967fc9804068691d to your computer and use it in GitHub Desktop.
Show a flyout project window in the scene view
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;
}
}
@DyofSeres
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment