This commit is contained in:
2026-07-09 21:33:33 +02:00
commit 84a2a365f3
2364 changed files with 950134 additions and 0 deletions
@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UIElements;
using PlayerInputManager = VOID.Generic.Player.Input.PlayerInputManager;
using ShortcutsInputManager = VOID.Generic.Player.Input.ShortcutsInputManager;
namespace VOID.UserInterface.Game.Util
{
[Serializable]
public class WindowUI : MonoBehaviour
{
public static List<WindowUI> openWindows = new();
// UI Visual Elements
private VisualElement _parentElement;
private VisualElement _rootElement;
private Button _windowCloseButton;
private VisualElement _headerElement;
private Label _titleLabel;
// Events
public event Action OnClose;
public event Action OnOpen;
// References
private PlayerInputManager _playerInputManager;
private GameUI _gameUI;
// Toggle
private bool _isOpen;
private bool _isOverHeader;
private bool _isDragging;
// Offset - relative position from window position to cursor
private Vector2 _draggingOffset;
private void Awake()
{
var uiDocument = gameObject.GetComponent<UIDocument>();
var templateElement = uiDocument.rootVisualElement;
// Find all visual elements
_rootElement = templateElement.Q("root-window");
_parentElement = _rootElement.parent.parent;
_headerElement = _rootElement.Q("header");
_titleLabel = _headerElement.Q<Label>("title");
_windowCloseButton = _rootElement.Q<Button>("close");
// Close backpack when "x" pressed
_windowCloseButton.clicked += Close;
// Make window active if pressed
_parentElement.RegisterCallback(new EventCallback<MouseDownEvent>(_ => SetActiveWindow()), TrickleDown.TrickleDown);
}
private void Start()
{
_gameUI = GameUI.current;
_playerInputManager = PlayerInputManager.current;
_playerInputManager.OnDraggingPrepare += PrepareDragging;
_playerInputManager.OnDraggingStart += StartDragging;
_playerInputManager.OnDraggingEnd += EndDragging;
}
public void SetTitle(string title)
{
_titleLabel.text = title;
}
public void Toggle()
{
if (_isOpen)
{
Close();
}
else
{
Open();
}
}
public void Close()
{
// Hide element
_parentElement.style.display = DisplayStyle.None;
// Reset element position styles
_parentElement.style.right = StyleKeyword.Null;
_parentElement.style.top = StyleKeyword.Null;
_parentElement.style.bottom = StyleKeyword.Null;
_parentElement.style.left = StyleKeyword.Null;
_isOpen = false;
OnClose?.Invoke();
openWindows.Remove(this);
}
public void Open()
{
// Show Element
_parentElement.style.display = DisplayStyle.Flex;
_isOpen = true;
OnOpen?.Invoke();
openWindows.Add(this);
SetActiveWindow();
}
private void Update()
{
if (!_isDragging) return;
var mousePos = _gameUI.cursorPositionOnUI;
_parentElement.style.top = new StyleLength(mousePos.y - Mathf.Abs(_draggingOffset.y));
_parentElement.style.left = new StyleLength(mousePos.x - Mathf.Abs(_draggingOffset.x));
}
private void PrepareDragging()
{
// Check if dragging started at window's title header...
_isOverHeader = GameUI.current.elementsUnderCursor.Contains(_headerElement);
// ...Only dragging by TITLE element allows to drag whole window
if (!_isOverHeader) return;
// Calculate offset from mouse position to window position
var windowPos = new Vector2(_parentElement.worldBound.x,_parentElement.worldBound.y);
var mousePos = _gameUI.cursorPositionOnUI;
_draggingOffset = windowPos - mousePos;
}
private void StartDragging()
{
if (!_isOverHeader) return;
_isDragging = true;
_parentElement.style.right = new StyleLength(StyleKeyword.Auto);
_parentElement.style.bottom = new StyleLength(StyleKeyword.Auto);
}
public void EndDragging()
{
_isDragging = false;
_isOverHeader = false;
}
public void SetActiveWindow()
{
openWindows.Remove(this);
openWindows = openWindows.Prepend(this).ToList();
UpdateDocumentUIOrder();
}
/// <summary>
/// Calculating sorting order for all windows (in which order they will be rendered)
/// </summary>
public static void UpdateDocumentUIOrder()
{
openWindows.ForEach(window =>
{
var sortingOrder = openWindows.Count - openWindows.IndexOf(window);
window.GetComponent<UIDocument>().sortingOrder = sortingOrder;
});
}
}
}