Files
2026-06-17 20:44:53 +03:00

169 lines
6.9 KiB
C#

#if UNITY_2021_3_OR_NEWER
using System;
using System.Collections.Generic;
using System.Reflection;
using SingularityGroup.HotReload.Editor.Localization;
using UnityEditor.Overlays;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEngine;
using UnityEditor.Toolbars;
namespace SingularityGroup.HotReload.Editor {
[Overlay(typeof(SceneView), Translations.MenuItems.OverlayDescription, true)]
[Icon("Assets/HotReload/Editor/Resources/Icon_DarkMode.png")]
internal class HotReloadOverlay : ToolbarOverlay {
HotReloadOverlay() : base(HotReloadToolbarLogoButton.id, HotReloadToolbarIndicationButton.id, HotReloadToolbarRecompileButton.id) {
EditorApplication.update += Update;
}
[EditorToolbarElement(id, typeof(SceneView))]
class HotReloadToolbarLogoButton : EditorToolbarButton, IAccessContainerWindow {
internal const string id = "HotReloadOverlay/LogoButton";
public EditorWindow containerWindow { get; set; }
bool lastShowingRedDot;
internal HotReloadToolbarLogoButton() {
icon = HotReloadState.ShowingRedDot ? GUIHelper.GetInvertibleIcon(InvertibleIcon.LogoNew) : GUIHelper.GetInvertibleIcon(InvertibleIcon.Logo);
tooltip = "Hot Reload";
clicked += OnClick;
EditorApplication.update += Update;
}
void OnClick() {
HotReloadWindow.Open();
if (HotReloadWindow.Current) {
HotReloadWindow.Current.SelectTab(typeof(HotReloadRunTab));
}
}
void Update() {
if (lastShowingRedDot != HotReloadState.ShowingRedDot) {
icon = HotReloadState.ShowingRedDot ? GUIHelper.GetInvertibleIcon(InvertibleIcon.LogoNew) : GUIHelper.GetInvertibleIcon(InvertibleIcon.Logo);
lastShowingRedDot = HotReloadState.ShowingRedDot;
}
}
~HotReloadToolbarLogoButton() {
clicked -= OnClick;
EditorApplication.update -= Update;
}
}
EditorIndicationState.IndicationStatus lastIndicationStatus;
[EditorToolbarElement(id, typeof(SceneView))]
class HotReloadToolbarIndicationButton : EditorToolbarButton, IAccessContainerWindow {
internal const string id = "HotReloadOverlay/IndicationButton";
public EditorWindow containerWindow { get; set; }
EditorIndicationState.IndicationStatus lastIndicationStatus;
internal HotReloadToolbarIndicationButton() {
icon = GetIndicationIcon();
tooltip = string.Format(Translations.Timeline.IndicationTooltip, EditorIndicationState.IndicationStatusText);
clicked += OnClick;
EditorApplication.update += Update;
}
void OnClick() {
HotReloadEventPopup.Open(PopupSource.Overlay, Event.current.mousePosition);
}
void Update() {
if (lastIndicationStatus != EditorIndicationState.CurrentIndicationStatus) {
icon = GetIndicationIcon();
tooltip = string.Format(Translations.Timeline.IndicationTooltip, EditorIndicationState.IndicationStatusText);
lastIndicationStatus = EditorIndicationState.CurrentIndicationStatus;
}
}
~HotReloadToolbarIndicationButton() {
clicked -= OnClick;
EditorApplication.update -= Update;
}
}
[EditorToolbarElement(id, typeof(SceneView))]
class HotReloadToolbarRecompileButton : EditorToolbarButton, IAccessContainerWindow {
internal const string id = "HotReloadOverlay/RecompileButton";
public EditorWindow containerWindow { get; set; }
private Texture2D refreshIcon => GUIHelper.GetInvertibleIcon(InvertibleIcon.Recompile);
internal HotReloadToolbarRecompileButton() {
icon = refreshIcon;
tooltip = Translations.Miscellaneous.OverlayTooltipRecompile;
clicked += HotReloadRunTab.RecompileWithChecks;
}
}
private static Texture2D latestIcon;
private static Dictionary<string, Texture2D> iconTextures = new Dictionary<string, Texture2D>();
private static Spinner spinner = new Spinner(100);
private static Texture2D GetIndicationIcon() {
if (EditorIndicationState.IndicationIconPath == null || EditorIndicationState.SpinnerActive) {
latestIcon = spinner.GetIcon();
} else {
latestIcon = GUIHelper.GetLocalIcon(EditorIndicationState.IndicationIconPath);
}
return latestIcon;
}
private static Image indicationIcon;
private static Label indicationText;
bool initialized;
/// <summary>
/// Create Hot Reload overlay panel.
/// </summary>
public override VisualElement CreatePanelContent() {
#if UNITY_2022_1_OR_NEWER
return CreateContent(Layout.HorizontalToolbar);
#elif UNITY_2021_3_OR_NEWER
return (VisualElement)typeof(Overlay).GetMethod("CreateContent", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(Layout)}, null)?.Invoke(this, new object[] {
Layout.HorizontalToolbar,
});
#endif
}
static bool _repaint;
static bool _instantRepaint;
static DateTime _lastRepaint;
private void Update() {
if (!initialized) {
return;
}
if (lastIndicationStatus != EditorIndicationState.CurrentIndicationStatus) {
indicationIcon.image = GetIndicationIcon();
indicationText.text = EditorIndicationState.IndicationStatusText;
lastIndicationStatus = EditorIndicationState.CurrentIndicationStatus;
}
try {
if (HotReloadEventPopup.I.open
&& EditorWindow.mouseOverWindow
&& EditorWindow.mouseOverWindow?.GetType() == typeof(UnityEditor.PopupWindow)
) {
_repaint = true;
}
} catch (NullReferenceException) {
// Unity randomly throws nullrefs when EditorWindow.mouseOverWindow gets accessed
}
if (_repaint && DateTime.UtcNow - _lastRepaint > TimeSpan.FromMilliseconds(33)) {
_repaint = false;
_instantRepaint = true;
}
if (_instantRepaint) {
HotReloadEventPopup.I.Repaint();
}
}
~HotReloadOverlay() {
EditorApplication.update -= Update;
}
}
}
#endif