SHA256
210 lines
6.8 KiB
C#
210 lines
6.8 KiB
C#
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 Image = UnityEngine.UI.Image;
|
|
|
|
namespace ADOFAIRenderer.UI;
|
|
|
|
internal class DialogButton
|
|
{
|
|
// ReSharper disable FieldCanBeMadeReadOnly.Global
|
|
public string Text;
|
|
public Action OnClick;
|
|
public Color? BackgroundColor;
|
|
// ReSharper restore FieldCanBeMadeReadOnly.Global
|
|
|
|
public DialogButton(string text, Action onClick, Color? backgroundColor = null)
|
|
{
|
|
Text = text;
|
|
OnClick = onClick;
|
|
BackgroundColor = backgroundColor;
|
|
}
|
|
}
|
|
|
|
internal class CommonWarningDialogUI : MonoBehaviour
|
|
{
|
|
public static CommonWarningDialogUI? Instance { get; private set; }
|
|
private readonly List<VisualElement> _disabledElements = new();
|
|
private O5Window? _window;
|
|
|
|
private void Awake()
|
|
{
|
|
Instance = this;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
_window?.Dispose();
|
|
_window = null;
|
|
|
|
foreach (var elem in _disabledElements)
|
|
{
|
|
if (elem != null)
|
|
{
|
|
elem.SetEnabled(true);
|
|
}
|
|
}
|
|
_disabledElements.Clear();
|
|
|
|
if (Instance == this)
|
|
{
|
|
Instance = null;
|
|
}
|
|
}
|
|
|
|
public static void ShowDialog(string title, string description, params DialogButton[] buttons)
|
|
{
|
|
if (buttons.Length == 0) return;
|
|
|
|
var obj = new GameObject("CommonWarningDialogUI");
|
|
DontDestroyOnLoad(obj);
|
|
var dialog = obj.AddComponent<CommonWarningDialogUI>();
|
|
dialog.Initialize(title, description, buttons);
|
|
}
|
|
|
|
private void Initialize(string title, string description, DialogButton[] buttons)
|
|
{
|
|
if (!UnityEngine.EventSystems.EventSystem.current)
|
|
{
|
|
var eventSystemObj = new GameObject("EventSystem");
|
|
eventSystemObj.transform.SetParent(transform);
|
|
eventSystemObj.AddComponent<UnityEngine.EventSystems.EventSystem>();
|
|
eventSystemObj.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
|
|
}
|
|
|
|
foreach (var doc in FindObjectsByType<UIDocument>(FindObjectsSortMode.None))
|
|
{
|
|
if (doc && doc.rootVisualElement is { enabledSelf: true })
|
|
{
|
|
doc.rootVisualElement.SetEnabled(false);
|
|
_disabledElements.Add(doc.rootVisualElement);
|
|
}
|
|
}
|
|
|
|
// Set UI layer (5)
|
|
gameObject.layer = 5;
|
|
|
|
// Canvas setup
|
|
var canvas = gameObject.AddComponent<Canvas>();
|
|
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
|
canvas.sortingOrder = 32766;
|
|
|
|
var scaler = gameObject.AddComponent<CanvasScaler>();
|
|
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
|
scaler.referenceResolution = new Vector2(1920, 1080);
|
|
scaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight;
|
|
scaler.matchWidthOrHeight = 0.5f;
|
|
|
|
gameObject.AddComponent<GraphicRaycaster>();
|
|
|
|
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<Image>();
|
|
bgImage.color = new Color(0f, 0f, 0f, 0.65f);
|
|
bgImage.raycastTarget = true;
|
|
|
|
var bgRect = bgPanelObj.GetComponent<RectTransform>();
|
|
bgRect.anchorMin = Vector2.zero;
|
|
bgRect.anchorMax = Vector2.one;
|
|
bgRect.offsetMin = Vector2.zero;
|
|
bgRect.offsetMax = Vector2.zero;
|
|
|
|
// 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<VerticalLayoutGroup>();
|
|
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.alignment = TextAlignmentOptions.Center;
|
|
descText.textWrappingMode = TextWrappingModes.Normal;
|
|
descText.lineSpacing = 6;
|
|
descText.color = new Color(0.88f, 0.88f, 0.88f, 1f);
|
|
|
|
// ReSharper disable once InconsistentNaming
|
|
var descLE = descText.gameObject.AddComponent<LayoutElement>();
|
|
descLE.flexibleWidth = 1f;
|
|
descLE.flexibleHeight = 1f;
|
|
|
|
// Button action row
|
|
var btnRowObj = new GameObject("ButtonRow");
|
|
btnRowObj.transform.SetParent(content, false);
|
|
var btnRowRect = btnRowObj.AddComponent<RectTransform>();
|
|
var btnRowLE = btnRowObj.AddComponent<LayoutElement>();
|
|
btnRowLE.preferredHeight = 40f;
|
|
btnRowLE.flexibleWidth = 1f;
|
|
|
|
var hLayout = btnRowObj.AddComponent<HorizontalLayoutGroup>();
|
|
hLayout.spacing = 10f;
|
|
hLayout.childAlignment = TextAnchor.MiddleCenter;
|
|
hLayout.childControlWidth = true;
|
|
hLayout.childControlHeight = true;
|
|
hLayout.childForceExpandWidth = true;
|
|
hLayout.childForceExpandHeight = true;
|
|
|
|
for (var i = 0; i < buttons.Length; i++)
|
|
{
|
|
var btnData = buttons[i];
|
|
var btn = O5Factory.Button(
|
|
ctx: ctx,
|
|
parent: btnRowRect,
|
|
onClick: () =>
|
|
{
|
|
try
|
|
{
|
|
btnData.OnClick();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Melon<RenderMod>.Logger.Error($"Dialog Button Click Event Error: {ex}");
|
|
}
|
|
Destroy(gameObject);
|
|
},
|
|
text: btnData.Text,
|
|
id: $"btn_dialog_{i}",
|
|
height: 40f
|
|
);
|
|
|
|
if (btnData.BackgroundColor.HasValue)
|
|
{
|
|
btn.NormalColor = btnData.BackgroundColor.Value;
|
|
btn.UpdateVisual();
|
|
}
|
|
|
|
var le = btn.Rect.gameObject.AddComponent<LayoutElement>();
|
|
le.flexibleWidth = 1f;
|
|
le.preferredHeight = 40f;
|
|
}
|
|
}
|
|
} |