using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using UnityEngine.InputSystem; namespace UI { /// /// A draggable window component with title bar dragging and close button functionality. /// Automatically creates UI structure on Awake. /// public class Window : MonoBehaviour { [Header("Window Settings")] [SerializeField] private Vector2 windowSize = new Vector2(600, 400); [SerializeField] private string windowTitle = "Window"; [SerializeField] private Color backgroundColor = new Color(0.2f, 0.2f, 0.2f, 1f); [SerializeField] private Color titleBarColor = new Color(0.3f, 0.3f, 0.3f, 1f); [SerializeField] private float titleBarHeight = 30f; private RectTransform rectTransform; private RectTransform titleBarRect; private Image titleBarImage; private bool isDragging = false; private Vector2 dragOffset; private bool wasMouseDownLastFrame = false; private void Awake() { rectTransform = GetComponent(); if (rectTransform == null) { rectTransform = gameObject.AddComponent(); } CreateUIStructure(); } private void Update() { // Fallback: Check for mouse down on title bar if interface didn't fire bool isMouseDown = Mouse.current.leftButton.isPressed; if (isMouseDown && !wasMouseDownLastFrame && !isDragging) { CheckTitleBarClick(); } wasMouseDownLastFrame = isMouseDown; HandleDragging(); } /// /// Fallback method to check if mouse clicked on title bar using raycasting /// private void CheckTitleBarClick() { Debug.Log("CheckTitleBarClick"); if (EventSystem.current == null) return; Vector2 mousePosition = Mouse.current.position.ReadValue(); // Use EventSystem to raycast PointerEventData pointerData = new PointerEventData(EventSystem.current); pointerData.position = mousePosition; var results = new System.Collections.Generic.List(); EventSystem.current.RaycastAll(pointerData, results); foreach (var result in results) { // Check if we hit the title bar (but not the close button or its children) Transform hitTransform = result.gameObject.transform; if (hitTransform.name == "TitleBar" && hitTransform.IsChildOf(transform)) { OnTitleBarPointerDown(mousePosition); break; } // If we hit a child of TitleBar, check if it's not the close button else if (hitTransform.IsChildOf(transform.Find("TitleBar"))) { // Skip if it's the close button or its children if (!hitTransform.name.Contains("CloseButton") && hitTransform.parent != null && hitTransform.parent.name != "CloseButton") { OnTitleBarPointerDown(mousePosition); break; } } } } /// /// Creates the UI structure: background, title bar, close button, and content area /// private void CreateUIStructure() { // Set up root RectTransform rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); rectTransform.sizeDelta = windowSize; rectTransform.anchoredPosition = Vector2.zero; // Create Background GameObject backgroundObj = new GameObject("Background"); backgroundObj.transform.SetParent(transform, false); Image backgroundImage = backgroundObj.AddComponent(); backgroundImage.color = backgroundColor; RectTransform backgroundRect = backgroundObj.GetComponent(); backgroundRect.anchorMin = Vector2.zero; backgroundRect.anchorMax = Vector2.one; backgroundRect.sizeDelta = Vector2.zero; backgroundRect.anchoredPosition = Vector2.zero; // Create Title Bar GameObject titleBarObj = new GameObject("TitleBar"); titleBarObj.transform.SetParent(transform, false); Image titleBarImage = titleBarObj.AddComponent(); titleBarImage.color = titleBarColor; titleBarRect = titleBarObj.GetComponent(); titleBarRect.anchorMin = new Vector2(0, 1); titleBarRect.anchorMax = new Vector2(1, 1); titleBarRect.pivot = new Vector2(0.5f, 1); titleBarRect.sizeDelta = new Vector2(0, titleBarHeight); titleBarRect.anchoredPosition = new Vector2(0, 0); this.titleBarImage = titleBarImage; // Add TitleBarDragHandler component for dragging TitleBarDragHandler dragHandler = titleBarObj.AddComponent(); dragHandler.Initialize(this); // Create Title Text GameObject titleTextObj = new GameObject("TitleText"); titleTextObj.transform.SetParent(titleBarObj.transform, false); Text titleText = titleTextObj.AddComponent(); titleText.text = windowTitle; titleText.color = Color.white; titleText.font = Resources.GetBuiltinResource("LegacyRuntime.ttf"); titleText.fontSize = 14; titleText.alignment = TextAnchor.MiddleLeft; RectTransform titleTextRect = titleTextObj.GetComponent(); titleTextRect.anchorMin = new Vector2(0, 0); titleTextRect.anchorMax = new Vector2(1, 1); titleTextRect.sizeDelta = new Vector2(-60, 0); // Leave space for close button titleTextRect.anchoredPosition = new Vector2(10, 0); // Create Close Button GameObject closeButtonObj = new GameObject("CloseButton"); closeButtonObj.transform.SetParent(titleBarObj.transform, false); Image closeButtonImage = closeButtonObj.AddComponent(); closeButtonImage.color = new Color(0.5f, 0.5f, 0.5f, 1f); Button closeButton = closeButtonObj.AddComponent