diff --git a/UI/CommonWarningDialogUI.cs b/UI/CommonWarningDialogUI.cs index 7403b96..86a8b8b 100644 --- a/UI/CommonWarningDialogUI.cs +++ b/UI/CommonWarningDialogUI.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using MelonLoader; +using O5Kit.Core; +using O5Kit.Factory; using TMPro; using UnityEngine; using UnityEngine.UI; using UnityEngine.UIElements; -using Button = UnityEngine.UI.Button; using Image = UnityEngine.UI.Image; namespace ADOFAIRenderer.UI; @@ -29,6 +31,7 @@ internal class CommonWarningDialogUI : MonoBehaviour { public static CommonWarningDialogUI? Instance { get; private set; } private readonly List _disabledElements = new(); + private O5Window? _window; private void Awake() { @@ -37,6 +40,9 @@ internal class CommonWarningDialogUI : MonoBehaviour private void OnDestroy() { + _window?.Dispose(); + _window = null; + foreach (var elem in _disabledElements) { if (elem != null) @@ -83,202 +89,122 @@ internal class CommonWarningDialogUI : MonoBehaviour // Set UI layer (5) gameObject.layer = 5; - + // Canvas setup var canvas = gameObject.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; - canvas.sortingOrder = 32766; // Just below FFmpegDownloadUI (32767) - - // Responsive Canvas Scaler setup + canvas.sortingOrder = 32766; + var scaler = gameObject.AddComponent(); scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.referenceResolution = new Vector2(1920, 1080); scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; scaler.matchWidthOrHeight = 0.5f; - + gameObject.AddComponent(); - - // 1. Create full screen overlay background - var bgPanelObj = new GameObject("BackgroundPanel"); + + var ctx = RendererUIManager.Context; + + // 1. Create full screen backdrop (scrim) to block background input + var bgPanelObj = new GameObject("Backdrop"); bgPanelObj.transform.SetParent(transform, false); bgPanelObj.layer = 5; - + var bgImage = bgPanelObj.AddComponent(); - bgImage.color = new Color(0f, 0f, 0f, 0.65f); // Dark transparent overlay + bgImage.color = new Color(0f, 0f, 0f, 0.65f); bgImage.raycastTarget = true; - + var bgRect = bgPanelObj.GetComponent(); bgRect.anchorMin = Vector2.zero; bgRect.anchorMax = Vector2.one; bgRect.offsetMin = Vector2.zero; bgRect.offsetMax = Vector2.zero; - - var font = ModAssets.NanumSquareNeoNormal; - - // 2. Create modal container - var modalContainerObj = new GameObject("ModalContainer"); - modalContainerObj.transform.SetParent(bgPanelObj.transform, false); - modalContainerObj.layer = 5; - - var modalImage = modalContainerObj.AddComponent(); - modalImage.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); // Matching background tone of existing UI - - var modalOutline = modalContainerObj.AddComponent(); - modalOutline.effectColor = Color.white; - modalOutline.effectDistance = new Vector2(3.0f, -3.0f); // Consistent with existing UI outline style - - var modalRect = modalContainerObj.GetComponent(); - modalRect.anchorMin = new Vector2(0.5f, 0.5f); - modalRect.anchorMax = new Vector2(0.5f, 0.5f); - modalRect.pivot = new Vector2(0.5f, 0.5f); - modalRect.sizeDelta = new Vector2(650, 360); - - // 3. Create title text - var titleObj = new GameObject("TitleText"); - titleObj.transform.SetParent(modalContainerObj.transform, false); - titleObj.layer = 5; - - var titleText = titleObj.AddComponent(); - titleText.text = title; - titleText.fontSize = 24; - titleText.font = font; - titleText.color = new Color(1.0f, 0.8f, 0.2f, 1.0f); // Orange/yellow tone matching warning theme - titleText.alignment = TextAlignmentOptions.Center; - - var titleRect = titleObj.GetComponent(); - titleRect.anchorMin = new Vector2(0, 1); - titleRect.anchorMax = new Vector2(1, 1); - titleRect.pivot = new Vector2(0.5f, 1); - titleRect.anchoredPosition = new Vector2(0, -35); - titleRect.sizeDelta = new Vector2(0, 40); - - // 4. Create description text - var descObj = new GameObject("DescriptionText"); - descObj.transform.SetParent(modalContainerObj.transform, false); - descObj.layer = 5; - - var descText = descObj.AddComponent(); + + // 2. Create actual native O5Window + _window = O5Window.Create(ctx, bgPanelObj.transform, new O5WindowOptions + { + Id = "RendererMod_WarningDialog", + Title = title, + Size = new Vector2(540, 240), + Draggable = true, + Resizable = false, + ShowCloseButton = false, + ShowOutline = true, + Padding = new RectOffset(16, 16, 16, 16) + }); + + // 3. Build content inside window.Content + var content = _window.Content; + + var vLayout = content.gameObject.AddComponent(); + vLayout.spacing = 16f; + vLayout.padding = new RectOffset(16, 16, 12, 12); + vLayout.childControlWidth = true; + vLayout.childControlHeight = true; + vLayout.childForceExpandWidth = true; + vLayout.childForceExpandHeight = false; + + // Description text + var descText = O5Factory.ControlText(ctx, content, 18f, noPad: true); descText.text = description; - descText.fontSize = 20; - descText.font = font; - descText.color = new Color(0.85f, 0.85f, 0.85f, 1f); descText.alignment = TextAlignmentOptions.Center; - descText.lineSpacing = 8; - - var descRect = descObj.GetComponent(); - descRect.anchorMin = new Vector2(0, 0.5f); - descRect.anchorMax = new Vector2(1, 1); - descRect.pivot = new Vector2(0.5f, 0.5f); - descRect.anchoredPosition = new Vector2(0, -65); - descRect.sizeDelta = new Vector2(-40, 120); - - // 5. Create button container - var buttonContainerObj = new GameObject("ButtonContainer", typeof(RectTransform)); - buttonContainerObj.transform.SetParent(modalContainerObj.transform, false); - buttonContainerObj.layer = 5; - - var btnContainerRect = buttonContainerObj.GetComponent(); - btnContainerRect.anchorMin = new Vector2(0, 0); - btnContainerRect.anchorMax = new Vector2(1, 0); - btnContainerRect.pivot = new Vector2(0.5f, 0); - btnContainerRect.anchoredPosition = new Vector2(0, 35); - btnContainerRect.sizeDelta = new Vector2(0, 50); + descText.textWrappingMode = TextWrappingModes.Normal; + descText.lineSpacing = 6; + descText.color = new Color(0.88f, 0.88f, 0.88f, 1f); - // 6. Dynamic button layout and styling - float totalWidth = 560f; - float spacing = 15f; - float buttonHeight = 45f; - int numButtons = buttons.Length; + // ReSharper disable once InconsistentNaming + var descLE = descText.gameObject.AddComponent(); + descLE.flexibleWidth = 1f; + descLE.flexibleHeight = 1f; - float buttonWidth = numButtons == 1 - ? 200f - : (totalWidth - (spacing * (numButtons - 1))) / numButtons; + // Button action row + var btnRowObj = new GameObject("ButtonRow"); + btnRowObj.transform.SetParent(content, false); + var btnRowRect = btnRowObj.AddComponent(); + var btnRowLE = btnRowObj.AddComponent(); + btnRowLE.preferredHeight = 40f; + btnRowLE.flexibleWidth = 1f; - float startX = numButtons == 1 - ? 0 - : (-totalWidth / 2f) + (buttonWidth / 2f); + var hLayout = btnRowObj.AddComponent(); + hLayout.spacing = 10f; + hLayout.childAlignment = TextAnchor.MiddleCenter; + hLayout.childControlWidth = true; + hLayout.childControlHeight = true; + hLayout.childForceExpandWidth = true; + hLayout.childForceExpandHeight = true; - for (int i = 0; i < numButtons; i++) + for (var i = 0; i < buttons.Length; i++) { var btnData = buttons[i]; - var btnObj = new GameObject($"Button_{i}"); - btnObj.transform.SetParent(buttonContainerObj.transform, false); - btnObj.layer = 5; + var btn = O5Factory.Button( + ctx: ctx, + parent: btnRowRect, + onClick: () => + { + try + { + btnData.OnClick(); + } + catch (Exception ex) + { + Melon.Logger.Error($"Dialog Button Click Event Error: {ex}"); + } + Destroy(gameObject); + }, + text: btnData.Text, + id: $"btn_dialog_{i}", + height: 40f + ); - // Define default colors - Color baseColor = btnData.BackgroundColor ?? new Color(0.2f, 0.2f, 0.23f, 1f); // Custom color or gray default - Color hoverColor = ApplyColorBrightness(baseColor, 1.2f); - Color pressedColor = ApplyColorBrightness(baseColor, 0.8f); - - var btnImage = btnObj.AddComponent(); - btnImage.color = baseColor; - btnImage.raycastTarget = true; - - var btn = btnObj.AddComponent