using System; using System.Collections; using System.Collections.Generic; using System.Runtime.Remoting.Contexts; using UnityEngine; using UnityEngine.UIElements; using UnityEngine.InputSystem; using BITKit; using Cysharp.Threading.Tasks; namespace BITKit.UX.Internal { public class ContextMenu : IContextMenu { public virtual VisualElement GetVisualElement() { return new VisualElement(); } } public class Label : ContextMenu { public Label(string text) { this.text = text; } string text; public override VisualElement GetVisualElement() { UnityEngine.UIElements.Label label = new(text); return label; } } [System.Serializable] public class TestContextMenu { public void Execute() { ContextMenuBuilder .Create() .BuildText("Tools") .BuildAction("Log", () => Debug.Log(nameof(ContextMenu))) .Build(); } } public class Button : ContextMenu { public Button(string text, params Action[] actions) { this.text = text; foreach (var x in actions) { action += x; } } string text; Action action; public override VisualElement GetVisualElement() { UnityEngine.UIElements.Button button = new(); button.clicked += action; button.text = text; return button; } } } namespace BITKit.UX { public interface IContextMenu { VisualElement GetVisualElement(); } public static class ContextMenuBuilderExtensions { public static ContextMenuBuilder BuildText(this ContextMenuBuilder self, string text) { self.Add(new Internal.Label(text)); return self; } public static ContextMenuBuilder BuildAction(this ContextMenuBuilder self, string text, Action action) { self.Add(new Internal.Button(text, action, self.Excute)); return self; } } public class ContextMenuBuilder { readonly List contexts = new(); public event Action OnExcuted; private ContextMenuBuilder() { } public static ContextMenuBuilder Create() { return new(); } public void Build() { UXContextMenu.Singleton.Create(this); } internal void Excute() { OnExcuted?.Invoke(); } public void Add(IContextMenu x) => contexts.Add(x); public IEnumerable GetContextMenus() => contexts.ToArray(); } public class UXContextMenu : MonoBehaviour { internal static UXContextMenu Singleton; [SerializeField] private UIDocument document; private VisualElement root; private VisualElement container; private void Awake() { Singleton = this; root = document.rootVisualElement; container = document.rootVisualElement[1]; root.Q("background-image").RegisterCallback(x => { Close(); }); Close(); } public void Create(ContextMenuBuilder builder) { var pos = Mouse.current.position.ReadValue(); pos.y = Screen.height - pos.y; pos = RuntimePanelUtils.ScreenToPanel(root.panel, pos); container.style.position = Position.Absolute; container.style.left = pos.x; container.style.top = pos.y; container.Clear(); root.SetActive(true); foreach (var context in builder.GetContextMenus()) { container.Add(context.GetVisualElement()); } builder.OnExcuted += Close; } void Close() { container.Clear(); root.SetActive(false); } } }