Utilize O5Kit System in Warning and Download Dialogs

This commit is contained in:
copecone committed 2026-10-10 15:57:40 +09:00
1 parent 00048b7b06
commit 863dcd2357
2 files changed
+199 -331

No files matched your search

+75 -149
View File
@@ -1,10 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using MelonLoader;
using O5Kit.Core;
using O5Kit.Factory;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using UnityEngine.UIElements; using UnityEngine.UIElements;
using Button = UnityEngine.UI.Button;
using Image = UnityEngine.UI.Image; using Image = UnityEngine.UI.Image;
namespace ADOFAIRenderer.UI; namespace ADOFAIRenderer.UI;
@@ -29,6 +31,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
{ {
public static CommonWarningDialogUI? Instance { get; private set; } public static CommonWarningDialogUI? Instance { get; private set; }
private readonly List<VisualElement> _disabledElements = new(); private readonly List<VisualElement> _disabledElements = new();
private O5Window? _window;
private void Awake() private void Awake()
{ {
@@ -37,6 +40,9 @@ internal class CommonWarningDialogUI : MonoBehaviour
private void OnDestroy() private void OnDestroy()
{ {
_window?.Dispose();
_window = null;
foreach (var elem in _disabledElements) foreach (var elem in _disabledElements)
{ {
if (elem != null) if (elem != null)
@@ -87,9 +93,8 @@ internal class CommonWarningDialogUI : MonoBehaviour
// Canvas setup // Canvas setup
var canvas = gameObject.AddComponent<Canvas>(); var canvas = gameObject.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = 32766; // Just below FFmpegDownloadUI (32767) canvas.sortingOrder = 32766;
// Responsive Canvas Scaler setup
var scaler = gameObject.AddComponent<CanvasScaler>(); var scaler = gameObject.AddComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920, 1080); scaler.referenceResolution = new Vector2(1920, 1080);
@@ -98,13 +103,15 @@ internal class CommonWarningDialogUI : MonoBehaviour
gameObject.AddComponent<GraphicRaycaster>(); gameObject.AddComponent<GraphicRaycaster>();
// 1. Create full screen overlay background var ctx = RendererUIManager.Context;
var bgPanelObj = new GameObject("BackgroundPanel");
// 1. Create full screen backdrop (scrim) to block background input
var bgPanelObj = new GameObject("Backdrop");
bgPanelObj.transform.SetParent(transform, false); bgPanelObj.transform.SetParent(transform, false);
bgPanelObj.layer = 5; bgPanelObj.layer = 5;
var bgImage = bgPanelObj.AddComponent<Image>(); 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; bgImage.raycastTarget = true;
var bgRect = bgPanelObj.GetComponent<RectTransform>(); var bgRect = bgPanelObj.GetComponent<RectTransform>();
@@ -113,112 +120,66 @@ internal class CommonWarningDialogUI : MonoBehaviour
bgRect.offsetMin = Vector2.zero; bgRect.offsetMin = Vector2.zero;
bgRect.offsetMax = Vector2.zero; bgRect.offsetMax = Vector2.zero;
var font = ModAssets.NanumSquareNeoNormal; // 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)
});
// 2. Create modal container // 3. Build content inside window.Content
var modalContainerObj = new GameObject("ModalContainer"); var content = _window.Content;
modalContainerObj.transform.SetParent(bgPanelObj.transform, false);
modalContainerObj.layer = 5;
var modalImage = modalContainerObj.AddComponent<Image>(); var vLayout = content.gameObject.AddComponent<VerticalLayoutGroup>();
modalImage.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); // Matching background tone of existing UI vLayout.spacing = 16f;
vLayout.padding = new RectOffset(16, 16, 12, 12);
vLayout.childControlWidth = true;
vLayout.childControlHeight = true;
vLayout.childForceExpandWidth = true;
vLayout.childForceExpandHeight = false;
var modalOutline = modalContainerObj.AddComponent<Outline>(); // Description text
modalOutline.effectColor = Color.white; var descText = O5Factory.ControlText(ctx, content, 18f, noPad: true);
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>();
descText.text = description; 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.alignment = TextAlignmentOptions.Center;
descText.lineSpacing = 8; descText.textWrappingMode = TextWrappingModes.Normal;
descText.lineSpacing = 6;
descText.color = new Color(0.88f, 0.88f, 0.88f, 1f);
var descRect = descObj.GetComponent<RectTransform>(); // ReSharper disable once InconsistentNaming
descRect.anchorMin = new Vector2(0, 0.5f); var descLE = descText.gameObject.AddComponent<LayoutElement>();
descRect.anchorMax = new Vector2(1, 1); descLE.flexibleWidth = 1f;
descRect.pivot = new Vector2(0.5f, 0.5f); descLE.flexibleHeight = 1f;
descRect.anchoredPosition = new Vector2(0, -65);
descRect.sizeDelta = new Vector2(-40, 120);
// 5. Create button container // Button action row
var buttonContainerObj = new GameObject("ButtonContainer", typeof(RectTransform)); var btnRowObj = new GameObject("ButtonRow");
buttonContainerObj.transform.SetParent(modalContainerObj.transform, false); btnRowObj.transform.SetParent(content, false);
buttonContainerObj.layer = 5; var btnRowRect = btnRowObj.AddComponent<RectTransform>();
var btnRowLE = btnRowObj.AddComponent<LayoutElement>();
btnRowLE.preferredHeight = 40f;
btnRowLE.flexibleWidth = 1f;
var btnContainerRect = buttonContainerObj.GetComponent<RectTransform>(); var hLayout = btnRowObj.AddComponent<HorizontalLayoutGroup>();
btnContainerRect.anchorMin = new Vector2(0, 0); hLayout.spacing = 10f;
btnContainerRect.anchorMax = new Vector2(1, 0); hLayout.childAlignment = TextAnchor.MiddleCenter;
btnContainerRect.pivot = new Vector2(0.5f, 0); hLayout.childControlWidth = true;
btnContainerRect.anchoredPosition = new Vector2(0, 35); hLayout.childControlHeight = true;
btnContainerRect.sizeDelta = new Vector2(0, 50); hLayout.childForceExpandWidth = true;
hLayout.childForceExpandHeight = true;
// 6. Dynamic button layout and styling for (var i = 0; i < buttons.Length; i++)
float totalWidth = 560f;
float spacing = 15f;
float buttonHeight = 45f;
int numButtons = buttons.Length;
float buttonWidth = numButtons == 1
? 200f
: (totalWidth - (spacing * (numButtons - 1))) / numButtons;
float startX = numButtons == 1
? 0
: (-totalWidth / 2f) + (buttonWidth / 2f);
for (int i = 0; i < numButtons; i++)
{ {
var btnData = buttons[i]; var btnData = buttons[i];
var btnObj = new GameObject($"Button_{i}"); var btn = O5Factory.Button(
btnObj.transform.SetParent(buttonContainerObj.transform, false); ctx: ctx,
btnObj.layer = 5; parent: btnRowRect,
onClick: () =>
// 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(() =>
{ {
try try
{ {
@@ -226,59 +187,24 @@ internal class CommonWarningDialogUI : MonoBehaviour
} }
catch (Exception ex) catch (Exception ex)
{ {
MelonLoader.Melon<RenderMod>.Logger.Error($"Dialog Button Click Event Error: {ex}"); Melon<RenderMod>.Logger.Error($"Dialog Button Click Event Error: {ex}");
} }
Destroy(gameObject); Destroy(gameObject);
}); },
text: btnData.Text,
id: $"btn_dialog_{i}",
height: 40f
);
var btnRect = btnObj.GetComponent<RectTransform>(); if (btnData.BackgroundColor.HasValue)
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);
// 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;
}
}
private void SetupButtonStyle(Button button, Color normalColor, Color hoverColor, Color pressedColor)
{ {
button.transition = Selectable.Transition.ColorTint; btn.NormalColor = btnData.BackgroundColor.Value;
var colors = button.colors; btn.UpdateVisual();
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) var le = btn.Rect.gameObject.AddComponent<LayoutElement>();
{ le.flexibleWidth = 1f;
float r = Mathf.Clamp01(color.r * factor); le.preferredHeight = 40f;
float g = Mathf.Clamp01(color.g * factor); }
float b = Mathf.Clamp01(color.b * factor);
return new Color(r, g, b, color.a);
} }
} }
+124 -182
View File
@@ -4,11 +4,13 @@ using System.IO.Compression;
using System.Net.Http; using System.Net.Http;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using MelonLoader;
using MelonLoader.Utils;
using O5Kit.Core;
using O5Kit.Factory;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
using MelonLoader;
using MelonLoader.Utils;
namespace ADOFAIRenderer.UI; namespace ADOFAIRenderer.UI;
@@ -22,6 +24,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
private GameObject _statusTextObj = null!; private GameObject _statusTextObj = null!;
private TextMeshProUGUI _statusText = null!; private TextMeshProUGUI _statusText = null!;
private O5Window? _window;
private bool _isDownloading; private bool _isDownloading;
private string DownloadUrl => Application.platform switch private string DownloadUrl => Application.platform switch
{ {
@@ -104,13 +107,15 @@ internal class FFmpegDownloadUI : MonoBehaviour
gameObject.AddComponent<GraphicRaycaster>(); gameObject.AddComponent<GraphicRaycaster>();
// 1. Create full screen overlay background var ctx = RendererUIManager.Context;
var bgPanelObj = new GameObject("BackgroundPanel");
// 1. Create full screen backdrop
var bgPanelObj = new GameObject("Backdrop");
bgPanelObj.transform.SetParent(transform, false); bgPanelObj.transform.SetParent(transform, false);
bgPanelObj.layer = 5; bgPanelObj.layer = 5;
var bgImage = bgPanelObj.AddComponent<Image>(); 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; bgImage.raycastTarget = true;
var bgRect = bgPanelObj.GetComponent<RectTransform>(); var bgRect = bgPanelObj.GetComponent<RectTransform>();
@@ -119,51 +124,31 @@ internal class FFmpegDownloadUI : MonoBehaviour
bgRect.offsetMin = Vector2.zero; bgRect.offsetMin = Vector2.zero;
bgRect.offsetMax = Vector2.zero; bgRect.offsetMax = Vector2.zero;
var font = ModAssets.NanumSquareNeoNormal; // 2. Create actual native O5Window
_window = O5Window.Create(ctx, bgPanelObj.transform, new O5WindowOptions
{
Id = "RendererMod_FFmpegDownloadDialog",
Title = "FFmpeg Library Installation Required",
Size = new Vector2(580, 270),
Draggable = true,
Resizable = false,
ShowCloseButton = false,
ShowOutline = true,
Padding = new RectOffset(16, 16, 16, 16)
});
// 2. Create modal container var content = _window.Content;
var modalContainerObj = new GameObject("ModalContainer");
modalContainerObj.transform.SetParent(bgPanelObj.transform, false);
modalContainerObj.layer = 5;
var modalImage = modalContainerObj.AddComponent<Image>(); var vLayout = content.gameObject.AddComponent<VerticalLayoutGroup>();
modalImage.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); vLayout.spacing = 14f;
vLayout.padding = new RectOffset(16, 16, 10, 10);
vLayout.childControlWidth = true;
vLayout.childControlHeight = true;
vLayout.childForceExpandWidth = true;
vLayout.childForceExpandHeight = false;
var modalOutline = modalContainerObj.AddComponent<Outline>(); // 3. Description text
modalOutline.effectColor = Color.white; var descText = O5Factory.ControlText(ctx, content, 18f, noPad: true);
modalOutline.effectDistance = new Vector2(3.0f, -3.0f);
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(600, 320);
// 4. Create title text
var titleObj = new GameObject("TitleText");
titleObj.transform.SetParent(modalContainerObj.transform, false);
titleObj.layer = 5;
var titleText = titleObj.AddComponent<TextMeshProUGUI>();
titleText.text = "FFmpeg Library Installation Required";
titleText.fontSize = 26;
titleText.font = font;
titleText.color = Color.white;
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);
// 5. Create description text
var descObj = new GameObject("DescriptionText");
descObj.transform.SetParent(modalContainerObj.transform, false);
descObj.layer = 5;
var descText = descObj.AddComponent<TextMeshProUGUI>();
var descStrBuilder = new StringBuilder(); var descStrBuilder = new StringBuilder();
descStrBuilder.AppendLine("FFmpeg shared libraries are required to render video."); descStrBuilder.AppendLine("FFmpeg shared libraries are required to render video.");
if (Application.platform == RuntimePlatform.OSXPlayer) if (Application.platform == RuntimePlatform.OSXPlayer)
@@ -176,139 +161,104 @@ internal class FFmpegDownloadUI : MonoBehaviour
descStrBuilder.AppendLine("Click the button below to automatically download and install from the internet."); descStrBuilder.AppendLine("Click the button below to automatically download and install from the internet.");
descStrBuilder.AppendLine("<color=#aaaaaa><size=13>(Download size: ~70MB, extracted to UserLibs folder)</size></color>"); descStrBuilder.AppendLine("<color=#aaaaaa><size=13>(Download size: ~70MB, extracted to UserLibs folder)</size></color>");
} }
descText.text = descStrBuilder.ToString(); descText.text = descStrBuilder.ToString();
descText.fontSize = 16;
descText.font = font;
descText.color = new Color(0.85f, 0.85f, 0.85f, 1f);
descText.alignment = TextAlignmentOptions.Center; descText.alignment = TextAlignmentOptions.Center;
descText.lineSpacing = 10; descText.textWrappingMode = TextWrappingModes.Normal;
descText.lineSpacing = 5;
descText.color = new Color(0.85f, 0.85f, 0.85f, 1f);
var descRect = descObj.GetComponent<RectTransform>(); var descLE = descText.gameObject.AddComponent<LayoutElement>();
descRect.anchorMin = new Vector2(0, 0.5f); descLE.flexibleWidth = 1f;
descRect.anchorMax = new Vector2(1, 1); descLE.flexibleHeight = 1f;
descRect.pivot = new Vector2(0.5f, 0.5f);
descRect.anchoredPosition = new Vector2(0, -60);
descRect.sizeDelta = new Vector2(-40, 100);
// 6. Create button container // 4. Button container
_buttonContainerObj = new GameObject("ButtonContainer", typeof(RectTransform)); _buttonContainerObj = new GameObject("ButtonContainer");
_buttonContainerObj.transform.SetParent(modalContainerObj.transform, false); _buttonContainerObj.transform.SetParent(content, false);
_buttonContainerObj.layer = 5; _buttonContainerObj.layer = 5;
var btnContainerRect = _buttonContainerObj.GetComponent<RectTransform>(); var btnContainerLE = _buttonContainerObj.AddComponent<LayoutElement>();
btnContainerRect.anchorMin = new Vector2(0, 0); btnContainerLE.preferredHeight = 40f;
btnContainerRect.anchorMax = new Vector2(1, 0); btnContainerLE.flexibleWidth = 1f;
btnContainerRect.pivot = new Vector2(0.5f, 0);
btnContainerRect.anchoredPosition = new Vector2(0, 35);
btnContainerRect.sizeDelta = new Vector2(0, 50);
// 7. Create download button var btnLayout = _buttonContainerObj.AddComponent<HorizontalLayoutGroup>();
var downloadBtnObj = new GameObject("DownloadButton"); btnLayout.spacing = 10f;
downloadBtnObj.transform.SetParent(_buttonContainerObj.transform, false); btnLayout.childAlignment = TextAnchor.MiddleCenter;
downloadBtnObj.layer = 5; btnLayout.childControlWidth = true;
btnLayout.childControlHeight = true;
btnLayout.childForceExpandWidth = true;
btnLayout.childForceExpandHeight = true;
var downloadImg = downloadBtnObj.AddComponent<Image>(); Action onDownloadClick = Application.platform != RuntimePlatform.OSXPlayer
downloadImg.color = new Color(0.0f, 0.8f, 1.0f, 1.0f); // Sleek cyan/blue ? StartDownloadProcess
downloadImg.raycastTarget = true; : () => { Application.OpenURL("https://ffmpeg.org"); Destroy(gameObject); };
var downloadBtn = downloadBtnObj.AddComponent<Button>(); var downloadBtn = O5Factory.Button(
SetupButtonStyle(downloadBtn, new Color(0.0f, 0.8f, 1.0f, 1.0f), new Color(0.2f, 0.9f, 1.0f, 1.0f), new Color(0.0f, 0.6f, 0.8f, 1.0f)); ctx: ctx,
if (Application.platform != RuntimePlatform.OSXPlayer) downloadBtn.onClick.AddListener(StartDownloadProcess); parent: _buttonContainerObj.transform,
else onClick: onDownloadClick,
{ text: Application.platform != RuntimePlatform.OSXPlayer ? "Download & Install" : "Open Website",
downloadBtn.onClick.AddListener(OpenFFmpegWebsite); id: "btn_ffmpeg_download",
void OpenFFmpegWebsite() { Application.OpenURL("https://ffmpeg.org"); Destroy(gameObject); } height: 40f
} );
downloadBtn.NormalColor = ctx.Theme.ObjectActiveBright;
downloadBtn.UpdateVisual();
var downloadBtnRect = downloadBtnObj.GetComponent<RectTransform>(); var downloadBtnLE = downloadBtn.Rect.gameObject.AddComponent<LayoutElement>();
downloadBtnRect.anchorMin = new Vector2(0.5f, 0.5f); downloadBtnLE.flexibleWidth = 1f;
downloadBtnRect.anchorMax = new Vector2(0.5f, 0.5f); downloadBtnLE.preferredHeight = 40f;
downloadBtnRect.pivot = new Vector2(1f, 0.5f);
downloadBtnRect.anchoredPosition = new Vector2(-15, 0);
downloadBtnRect.sizeDelta = new Vector2(180, 45);
var downloadTextObj = new GameObject("DownloadText"); var cancelBtn = O5Factory.Button(
downloadTextObj.transform.SetParent(downloadBtnObj.transform, false); ctx: ctx,
downloadTextObj.layer = 5; parent: _buttonContainerObj.transform,
onClick: CancelProcess,
text: "Cancel",
id: "btn_ffmpeg_cancel",
height: 40f
);
var cancelBtnLE = cancelBtn.Rect.gameObject.AddComponent<LayoutElement>();
cancelBtnLE.flexibleWidth = 1f;
cancelBtnLE.preferredHeight = 40f;
var downloadText = downloadTextObj.AddComponent<TextMeshProUGUI>(); // 5. Progress bar container
downloadText.text = Application.platform != RuntimePlatform.OSXPlayer ? "Download & Install" : "Open Website";
downloadText.fontSize = 20;
downloadText.font = font;
downloadText.color = Color.white;
downloadText.alignment = TextAlignmentOptions.Center;
var downloadTextRect = downloadTextObj.GetComponent<RectTransform>();
downloadTextRect.anchorMin = Vector2.zero;
downloadTextRect.anchorMax = Vector2.one;
downloadTextRect.offsetMin = Vector2.zero;
downloadTextRect.offsetMax = Vector2.zero;
// 8. Create cancel button
var cancelBtnObj = new GameObject("CancelButton");
cancelBtnObj.transform.SetParent(_buttonContainerObj.transform, false);
cancelBtnObj.layer = 5;
var cancelImg = cancelBtnObj.AddComponent<Image>();
cancelImg.color = new Color(0.2f, 0.2f, 0.23f, 1f);
cancelImg.raycastTarget = true;
var cancelBtn = cancelBtnObj.AddComponent<Button>();
SetupButtonStyle(cancelBtn, new Color(0.2f, 0.2f, 0.23f, 1f), new Color(0.25f, 0.25f, 0.28f, 1f), new Color(0.15f, 0.15f, 0.18f, 1f));
cancelBtn.onClick.AddListener(CancelProcess);
var cancelBtnRect = cancelBtnObj.GetComponent<RectTransform>();
cancelBtnRect.anchorMin = new Vector2(0.5f, 0.5f);
cancelBtnRect.anchorMax = new Vector2(0.5f, 0.5f);
cancelBtnRect.pivot = new Vector2(0f, 0.5f);
cancelBtnRect.anchoredPosition = new Vector2(15, 0);
cancelBtnRect.sizeDelta = new Vector2(180, 45);
var cancelTextObj = new GameObject("CancelText");
cancelTextObj.transform.SetParent(cancelBtnObj.transform, false);
cancelTextObj.layer = 5;
var cancelText = cancelTextObj.AddComponent<TextMeshProUGUI>();
cancelText.text = "Cancel";
cancelText.fontSize = 20;
cancelText.font = font;
cancelText.color = new Color(0.9f, 0.9f, 0.9f, 1f);
cancelText.alignment = TextAlignmentOptions.Center;
var cancelTextRect = cancelTextObj.GetComponent<RectTransform>();
cancelTextRect.anchorMin = Vector2.zero;
cancelTextRect.anchorMax = Vector2.one;
cancelTextRect.offsetMin = Vector2.zero;
cancelTextRect.offsetMax = Vector2.zero;
// 9. Create progress bar container
_progressBarObj = new GameObject("ProgressBarContainer"); _progressBarObj = new GameObject("ProgressBarContainer");
_progressBarObj.transform.SetParent(modalContainerObj.transform, false); _progressBarObj.transform.SetParent(content, false);
_progressBarObj.layer = 5; _progressBarObj.layer = 5;
_progressBarObj.SetActive(false); _progressBarObj.SetActive(false);
var pbLE = _progressBarObj.AddComponent<LayoutElement>();
pbLE.preferredHeight = 24f;
pbLE.flexibleWidth = 1f;
var barBgImg = _progressBarObj.AddComponent<Image>(); var barBgImg = _progressBarObj.AddComponent<Image>();
barBgImg.color = new Color(0.08f, 0.08f, 0.1f, 1.0f); barBgImg.sprite = ctx.Sprites.RoundedControl;
barBgImg.type = Image.Type.Sliced;
barBgImg.color = ctx.Theme.ObjectBG;
var barBgOutline = _progressBarObj.AddComponent<Outline>(); var barOutlineObj = new GameObject("BarOutline");
barBgOutline.effectColor = Color.white; barOutlineObj.transform.SetParent(_progressBarObj.transform, false);
barBgOutline.effectDistance = new Vector2(3.0f, -3.0f); barOutlineObj.layer = 5;
var barRect = _progressBarObj.GetComponent<RectTransform>(); var barOutlineImg = barOutlineObj.AddComponent<Image>();
barRect.anchorMin = new Vector2(0.5f, 0); barOutlineImg.sprite = ctx.Sprites.RoundedOutline;
barRect.anchorMax = new Vector2(0.5f, 0); barOutlineImg.type = Image.Type.Sliced;
barRect.pivot = new Vector2(0.5f, 0); barOutlineImg.color = ctx.Theme.ControlOutlineIdle;
barRect.anchoredPosition = new Vector2(0, 75); barOutlineImg.raycastTarget = false;
barRect.sizeDelta = new Vector2(480, 24);
// 10. Create progress bar fill image var barOutlineRect = barOutlineObj.GetComponent<RectTransform>();
barOutlineRect.anchorMin = Vector2.zero;
barOutlineRect.anchorMax = Vector2.one;
barOutlineRect.offsetMin = Vector2.zero;
barOutlineRect.offsetMax = Vector2.zero;
// Progress bar fill image
_progressBarFillObj = new GameObject("ProgressBarFill"); _progressBarFillObj = new GameObject("ProgressBarFill");
_progressBarFillObj.transform.SetParent(_progressBarObj.transform, false); _progressBarFillObj.transform.SetParent(_progressBarObj.transform, false);
_progressBarFillObj.layer = 5; _progressBarFillObj.layer = 5;
var fillImg = _progressBarFillObj.AddComponent<Image>(); var fillImg = _progressBarFillObj.AddComponent<Image>();
fillImg.color = new Color(0.0f, 0.8f, 1.0f, 1.0f); fillImg.sprite = ctx.Sprites.RoundedControl;
fillImg.type = Image.Type.Sliced;
fillImg.color = ctx.Theme.ObjectActiveBright;
_fillRect = _progressBarFillObj.GetComponent<RectTransform>(); _fillRect = _progressBarFillObj.GetComponent<RectTransform>();
_fillRect.anchorMin = new Vector2(0, 0); _fillRect.anchorMin = new Vector2(0, 0);
@@ -317,20 +267,17 @@ internal class FFmpegDownloadUI : MonoBehaviour
_fillRect.anchoredPosition = Vector2.zero; _fillRect.anchoredPosition = Vector2.zero;
_fillRect.sizeDelta = Vector2.zero; _fillRect.sizeDelta = Vector2.zero;
// 11. Create progress text // Progress text
var progressTextObj = new GameObject("ProgressBarText"); var progressTextObj = new GameObject("ProgressBarText");
progressTextObj.transform.SetParent(_progressBarObj.transform, false); progressTextObj.transform.SetParent(_progressBarObj.transform, false);
progressTextObj.layer = 5; progressTextObj.layer = 5;
_progressText = progressTextObj.AddComponent<TextMeshProUGUI>(); _progressText = progressTextObj.AddComponent<TextMeshProUGUI>();
_progressText.fontSize = 16; _progressText.fontSize = 13;
_progressText.font = font; _progressText.font = ctx.Fonts.Regular;
_progressText.color = Color.white; _progressText.color = Color.white;
_progressText.alignment = TextAlignmentOptions.Center; _progressText.alignment = TextAlignmentOptions.Center;
_progressText.raycastTarget = false;
var progressTextOutline = progressTextObj.AddComponent<Outline>();
progressTextOutline.effectColor = new Color(0, 0, 0, 0.8f);
progressTextOutline.effectDistance = new Vector2(1, -1);
var progressTextRect = progressTextObj.GetComponent<RectTransform>(); var progressTextRect = progressTextObj.GetComponent<RectTransform>();
progressTextRect.anchorMin = Vector2.zero; progressTextRect.anchorMin = Vector2.zero;
@@ -338,35 +285,28 @@ internal class FFmpegDownloadUI : MonoBehaviour
progressTextRect.offsetMin = Vector2.zero; progressTextRect.offsetMin = Vector2.zero;
progressTextRect.offsetMax = Vector2.zero; progressTextRect.offsetMax = Vector2.zero;
// 12. Create status text // 6. Status text
_statusTextObj = new GameObject("StatusText"); _statusTextObj = new GameObject("StatusText");
_statusTextObj.transform.SetParent(modalContainerObj.transform, false); _statusTextObj.transform.SetParent(content, false);
_statusTextObj.layer = 5; _statusTextObj.layer = 5;
_statusTextObj.SetActive(false); _statusTextObj.SetActive(false);
var statusLE = _statusTextObj.AddComponent<LayoutElement>();
statusLE.preferredHeight = 22f;
statusLE.flexibleWidth = 1f;
_statusText = _statusTextObj.AddComponent<TextMeshProUGUI>(); _statusText = _statusTextObj.AddComponent<TextMeshProUGUI>();
_statusText.fontSize = 16; _statusText.fontSize = 14;
_statusText.font = font; _statusText.font = ctx.Fonts.Regular;
_statusText.color = new Color(0.8f, 0.8f, 0.8f, 1f); _statusText.color = new Color(0.8f, 0.8f, 0.8f, 1f);
_statusText.alignment = TextAlignmentOptions.Center; _statusText.alignment = TextAlignmentOptions.Center;
_statusText.raycastTarget = false;
var statusRect = _statusTextObj.GetComponent<RectTransform>(); var statusRect = _statusTextObj.GetComponent<RectTransform>();
statusRect.anchorMin = new Vector2(0, 0); statusRect.anchorMin = Vector2.zero;
statusRect.anchorMax = new Vector2(1, 0); statusRect.anchorMax = Vector2.one;
statusRect.pivot = new Vector2(0.5f, 0); statusRect.offsetMin = Vector2.zero;
statusRect.anchoredPosition = new Vector2(0, 35); statusRect.offsetMax = Vector2.zero;
statusRect.sizeDelta = new Vector2(0, 30);
}
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 void Update() private void Update()
@@ -643,6 +583,8 @@ internal class FFmpegDownloadUI : MonoBehaviour
private void OnDestroy() private void OnDestroy()
{ {
_window?.Dispose();
_window = null;
_cts?.Dispose(); _cts?.Dispose();
if (Instance == this) if (Instance == this)
{ {