SHA256
Utilize O5Kit System in Warning and Download Dialogs
This commit is contained in:
2 files changed
+243
-375
No files matched your search
+94
-168
@@ -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<VisualElement> _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>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 32766; // Just below FFmpegDownloadUI (32767)
|
||||
|
||||
// Responsive Canvas Scaler setup
|
||||
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>();
|
||||
|
||||
// 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<Image>();
|
||||
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<RectTransform>();
|
||||
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<Image>();
|
||||
modalImage.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); // Matching background tone of existing UI
|
||||
|
||||
var modalOutline = modalContainerObj.AddComponent<Outline>();
|
||||
modalOutline.effectColor = Color.white;
|
||||
modalOutline.effectDistance = new Vector2(3.0f, -3.0f); // Consistent with existing UI outline style
|
||||
|
||||
var modalRect = modalContainerObj.GetComponent<RectTransform>();
|
||||
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<TextMeshProUGUI>();
|
||||
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<RectTransform>();
|
||||
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<TextMeshProUGUI>();
|
||||
|
||||
// 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.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<RectTransform>();
|
||||
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<RectTransform>();
|
||||
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<LayoutElement>();
|
||||
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<RectTransform>();
|
||||
var btnRowLE = btnRowObj.AddComponent<LayoutElement>();
|
||||
btnRowLE.preferredHeight = 40f;
|
||||
btnRowLE.flexibleWidth = 1f;
|
||||
|
||||
float startX = numButtons == 1
|
||||
? 0
|
||||
: (-totalWidth / 2f) + (buttonWidth / 2f);
|
||||
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 (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<RenderMod>.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<Image>();
|
||||
btnImage.color = baseColor;
|
||||
btnImage.raycastTarget = true;
|
||||
|
||||
var btn = btnObj.AddComponent<Button>();
|
||||
SetupButtonStyle(btn, baseColor, hoverColor, pressedColor);
|
||||
|
||||
// Register click callback
|
||||
btn.onClick.AddListener(() =>
|
||||
if (btnData.BackgroundColor.HasValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
btnData.OnClick();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MelonLoader.Melon<RenderMod>.Logger.Error($"Dialog Button Click Event Error: {ex}");
|
||||
}
|
||||
Destroy(gameObject);
|
||||
});
|
||||
|
||||
var btnRect = btnObj.GetComponent<RectTransform>();
|
||||
btnRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
btnRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
btnRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
|
||||
float posX = numButtons == 1
|
||||
? 0
|
||||
: startX + i * (buttonWidth + spacing);
|
||||
|
||||
btnRect.anchoredPosition = new Vector2(posX, 0);
|
||||
btnRect.sizeDelta = new Vector2(buttonWidth, buttonHeight);
|
||||
btn.NormalColor = btnData.BackgroundColor.Value;
|
||||
btn.UpdateVisual();
|
||||
}
|
||||
|
||||
// Add text label
|
||||
var txtObj = new GameObject("Text");
|
||||
txtObj.transform.SetParent(btnObj.transform, false);
|
||||
txtObj.layer = 5;
|
||||
|
||||
var text = txtObj.AddComponent<TextMeshProUGUI>();
|
||||
text.text = btnData.Text;
|
||||
text.fontSize = 20;
|
||||
text.font = font;
|
||||
text.color = Color.white;
|
||||
text.alignment = TextAlignmentOptions.Center;
|
||||
|
||||
var txtRect = txtObj.GetComponent<RectTransform>();
|
||||
txtRect.anchorMin = Vector2.zero;
|
||||
txtRect.anchorMax = Vector2.one;
|
||||
txtRect.offsetMin = Vector2.zero;
|
||||
txtRect.offsetMax = Vector2.zero;
|
||||
var le = btn.Rect.gameObject.AddComponent<LayoutElement>();
|
||||
le.flexibleWidth = 1f;
|
||||
le.preferredHeight = 40f;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupButtonStyle(Button button, Color normalColor, Color hoverColor, Color pressedColor)
|
||||
{
|
||||
button.transition = Selectable.Transition.ColorTint;
|
||||
var colors = button.colors;
|
||||
colors.normalColor = normalColor;
|
||||
colors.highlightedColor = hoverColor;
|
||||
colors.pressedColor = pressedColor;
|
||||
colors.disabledColor = new Color(0.3f, 0.3f, 0.3f, 1f);
|
||||
button.colors = colors;
|
||||
}
|
||||
|
||||
private Color ApplyColorBrightness(Color color, float factor)
|
||||
{
|
||||
float r = Mathf.Clamp01(color.r * factor);
|
||||
float g = Mathf.Clamp01(color.g * factor);
|
||||
float b = Mathf.Clamp01(color.b * factor);
|
||||
return new Color(r, g, b, color.a);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user