SHA256
Translate Codebase Comments and Log Messages to English
This commit is contained in:
23 files changed
+915
-921
No files matched your search
+20
-20
@@ -63,11 +63,11 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 로딩 실패
|
||||
// Loading failed
|
||||
}
|
||||
}
|
||||
|
||||
// 폴백 처리
|
||||
// Fallback processing
|
||||
if (!font)
|
||||
{
|
||||
try
|
||||
@@ -121,15 +121,15 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
// UI 레이어(5) 설정
|
||||
// Set UI layer (5)
|
||||
gameObject.layer = 5;
|
||||
|
||||
// Canvas 설정
|
||||
// Canvas setup
|
||||
var canvas = gameObject.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 32766; // FFmpegDownloadUI(32767) 바로 아래
|
||||
canvas.sortingOrder = 32766; // Just below FFmpegDownloadUI (32767)
|
||||
|
||||
// 해상도 대응 캔버스 스케일러 설정
|
||||
// Responsive Canvas Scaler setup
|
||||
var scaler = gameObject.AddComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
@@ -138,13 +138,13 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
|
||||
gameObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
// 1. 전체 화면 오버레이 배경 생성
|
||||
// 1. Create full screen overlay background
|
||||
var bgPanelObj = new GameObject("BackgroundPanel");
|
||||
bgPanelObj.transform.SetParent(transform, false);
|
||||
bgPanelObj.layer = 5;
|
||||
|
||||
var bgImage = bgPanelObj.AddComponent<Image>();
|
||||
bgImage.color = new Color(0f, 0f, 0f, 0.65f); // 어두운 투명 오버레이
|
||||
bgImage.color = new Color(0f, 0f, 0f, 0.65f); // Dark transparent overlay
|
||||
bgImage.raycastTarget = true;
|
||||
|
||||
var bgRect = bgPanelObj.GetComponent<RectTransform>();
|
||||
@@ -155,17 +155,17 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
|
||||
var font = GetNanumSquareNeoBdFontAsset();
|
||||
|
||||
// 2. 모달 컨테이너 생성
|
||||
// 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); // 기존 UI의 배경 톤과 동일
|
||||
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); // 기존 UI 외곽선 스타일 일관성
|
||||
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);
|
||||
@@ -173,7 +173,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
modalRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
modalRect.sizeDelta = new Vector2(650, 360);
|
||||
|
||||
// 3. 타이틀 텍스트 생성
|
||||
// 3. Create title text
|
||||
var titleObj = new GameObject("TitleText");
|
||||
titleObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
titleObj.layer = 5;
|
||||
@@ -182,7 +182,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
titleText.text = title;
|
||||
titleText.fontSize = 24;
|
||||
titleText.font = font;
|
||||
titleText.color = new Color(1.0f, 0.8f, 0.2f, 1.0f); // 경고 테마에 맞는 주황/황색 계열
|
||||
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>();
|
||||
@@ -192,7 +192,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
titleRect.anchoredPosition = new Vector2(0, -35);
|
||||
titleRect.sizeDelta = new Vector2(0, 40);
|
||||
|
||||
// 4. 본문 설명 텍스트 생성
|
||||
// 4. Create description text
|
||||
var descObj = new GameObject("DescriptionText");
|
||||
descObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
descObj.layer = 5;
|
||||
@@ -212,7 +212,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
descRect.anchoredPosition = new Vector2(0, -65);
|
||||
descRect.sizeDelta = new Vector2(-40, 120);
|
||||
|
||||
// 5. 버튼 컨테이너 생성
|
||||
// 5. Create button container
|
||||
var buttonContainerObj = new GameObject("ButtonContainer", typeof(RectTransform));
|
||||
buttonContainerObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
buttonContainerObj.layer = 5;
|
||||
@@ -224,7 +224,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
btnContainerRect.anchoredPosition = new Vector2(0, 35);
|
||||
btnContainerRect.sizeDelta = new Vector2(0, 50);
|
||||
|
||||
// 6. 가변 버튼 동적 배치 및 스타일링
|
||||
// 6. Dynamic button layout and styling
|
||||
float totalWidth = 560f;
|
||||
float spacing = 15f;
|
||||
float buttonHeight = 45f;
|
||||
@@ -245,8 +245,8 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
btnObj.transform.SetParent(buttonContainerObj.transform, false);
|
||||
btnObj.layer = 5;
|
||||
|
||||
// 기본 색상 정의
|
||||
Color baseColor = btnData.BackgroundColor ?? new Color(0.2f, 0.2f, 0.23f, 1f); // 커스텀 색상 또는 회색톤 기본값
|
||||
// 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);
|
||||
|
||||
@@ -257,7 +257,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
var btn = btnObj.AddComponent<Button>();
|
||||
SetupButtonStyle(btn, baseColor, hoverColor, pressedColor);
|
||||
|
||||
// 클릭 콜백 등록
|
||||
// Register click callback
|
||||
btn.onClick.AddListener(() =>
|
||||
{
|
||||
try
|
||||
@@ -283,7 +283,7 @@ internal class CommonWarningDialogUI : MonoBehaviour
|
||||
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;
|
||||
|
||||
+18
-18
@@ -15,14 +15,14 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
private const float BarHeight = 28f;
|
||||
private const float BarPosX = 0f;
|
||||
private const float BarPosY = -420f; // Y position relative to screen center (Reference: 1920x1080)
|
||||
private const int BarTextFontSize = 16; // 눈에 띄게 증가된 텍스트 크기
|
||||
private const int BarTextFontSize = 16; // Increased font size for visibility
|
||||
private static readonly Color BarBackgroundColor = new(0.08f, 0.08f, 0.1f, 1.0f);
|
||||
private static readonly Color BarFillColor = new(0.0f, 0.8f, 1.0f, 1.0f); // Sleek cyan/blue
|
||||
private static readonly Color BarTextColor = new(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
// --- Progress Bar Outline Configuration Constants ---
|
||||
private static readonly Color BarOutlineColor = Color.white; // 대비되는 흰색 윤곽선
|
||||
private static readonly Vector2 BarOutlineDistance = new(3.0f, -3.0f); // 3px의 굵고 직관적인 윤곽선 두께
|
||||
private static readonly Color BarOutlineColor = Color.white; // Contrasting white outline
|
||||
private static readonly Vector2 BarOutlineDistance = new(3.0f, -3.0f); // Outline thickness
|
||||
|
||||
private TextMeshProUGUI _text = null!;
|
||||
private GameObject _progressBarObj = null!;
|
||||
@@ -41,11 +41,11 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 로딩 실패
|
||||
// Loading failed
|
||||
}
|
||||
}
|
||||
|
||||
// 폴백 처리: 에셋 번들에서 실패 시 게임 자체 NanumSquareNeo 또는 내장 TMP SDF 폰트 사용
|
||||
// Fallback: Use game's own font or built-in TMP SDF font if AssetBundle loading fails
|
||||
if (font == null)
|
||||
{
|
||||
font = RDString.fontData.fontTMP;
|
||||
@@ -65,15 +65,15 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// UI 레이어(5) 설정
|
||||
// Set UI layer (5)
|
||||
gameObject.layer = 5;
|
||||
|
||||
// Canvas 설정
|
||||
// Canvas setup
|
||||
var canvas = gameObject.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 9999;
|
||||
|
||||
// 해상도 다이내믹 스케일링 설정 (Reference: 1920x1080)
|
||||
// Dynamic resolution scaling setup (Reference: 1920x1080)
|
||||
var scaler = gameObject.AddComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
@@ -82,13 +82,13 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
|
||||
gameObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
// 배경 패널 생성
|
||||
// Create background panel
|
||||
var panelObj = new GameObject("BackgroundPanel");
|
||||
panelObj.transform.SetParent(transform, false);
|
||||
panelObj.layer = 5;
|
||||
|
||||
var image = panelObj.AddComponent<Image>();
|
||||
image.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); // 약간 더 고급스러운 다크톤 아크릴 감성
|
||||
image.color = new Color(0.08f, 0.08f, 0.1f, 0.88f); // Dark tone acrylic style
|
||||
|
||||
var panelRect = panelObj.GetComponent<RectTransform>();
|
||||
panelRect.anchorMin = new Vector2(1, 1);
|
||||
@@ -97,28 +97,28 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
panelRect.anchoredPosition = new Vector2(-30, -30);
|
||||
panelRect.sizeDelta = new Vector2(360, 220);
|
||||
|
||||
// 텍스트 생성
|
||||
// Create text
|
||||
var textObj = new GameObject("MonitorText");
|
||||
textObj.transform.SetParent(panelObj.transform, false);
|
||||
textObj.layer = 5;
|
||||
|
||||
_text = textObj.AddComponent<TextMeshProUGUI>();
|
||||
_text.richText = true;
|
||||
_text.fontSize = 16; // 13에서 16으로 증가
|
||||
_text.fontSize = 16;
|
||||
_text.alignment = TextAlignmentOptions.TopLeft;
|
||||
|
||||
// TMPro 텍스트 잘림 현상 예방
|
||||
// Prevent TMPro text clipping
|
||||
_text.textWrappingMode = TextWrappingModes.Normal;
|
||||
_text.overflowMode = TextOverflowModes.Overflow;
|
||||
|
||||
// NanumSquareNeo-Bd SDF 폰트 로드 및 적용
|
||||
// Load and apply font
|
||||
var font = GetNanumSquareNeoBdFontAsset();
|
||||
_text.font = font;
|
||||
|
||||
var textRect = textObj.GetComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = new Vector2(20, 20); // 좀 더 넉넉하고 패딩 여백
|
||||
textRect.offsetMin = new Vector2(20, 20); // Padding margin
|
||||
textRect.offsetMax = new Vector2(-20, -20);
|
||||
|
||||
// --- Progress Bar UI Setup ---
|
||||
@@ -130,7 +130,7 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
var bgImage = _progressBarObj.AddComponent<Image>();
|
||||
bgImage.color = BarBackgroundColor;
|
||||
|
||||
// 프로그레스 바 흰색 윤곽선 컴포넌트 추가
|
||||
// Add progress bar outline component
|
||||
var bgOutline = _progressBarObj.AddComponent<Outline>();
|
||||
bgOutline.effectColor = BarOutlineColor;
|
||||
bgOutline.effectDistance = BarOutlineDistance;
|
||||
@@ -164,12 +164,12 @@ internal class DebugMonitorUI : MonoBehaviour
|
||||
|
||||
_progressText = progressTextObj.AddComponent<TextMeshProUGUI>();
|
||||
_progressText.richText = true;
|
||||
_progressText.fontSize = BarTextFontSize; // 14에서 18로 증가
|
||||
_progressText.fontSize = BarTextFontSize;
|
||||
_progressText.alignment = TextAlignmentOptions.Center;
|
||||
_progressText.font = font;
|
||||
_progressText.color = BarTextColor;
|
||||
|
||||
// 프로그레스 바 내부 텍스트 아웃라인 추가 (진행율 가독성 확보)
|
||||
// Add progress bar text outline for readability
|
||||
var textOutline = progressTextObj.AddComponent<Outline>();
|
||||
textOutline.effectColor = new Color(0f, 0f, 0f, 0.9f);
|
||||
textOutline.effectDistance = new Vector2(1.5f, -1.5f);
|
||||
|
||||
+17
-18
@@ -14,15 +14,15 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// UI 레이어(5) 설정
|
||||
// Set UI layer (5)
|
||||
gameObject.layer = 5;
|
||||
|
||||
// Canvas 설정
|
||||
// Canvas setup
|
||||
var canvas = gameObject.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 10000; // 디버그 모니터보다 위에 오도록 설정
|
||||
canvas.sortingOrder = 10000; // Placed above debug monitor
|
||||
|
||||
// 해상도 대응 캔버스 스케일러 설정
|
||||
// Responsive Canvas Scaler setup
|
||||
var scaler = gameObject.AddComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
@@ -31,23 +31,22 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
|
||||
gameObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
// 1. 컨테이너 및 배경 패널 오브젝트 생성
|
||||
// 1. Create container and background panel object
|
||||
_containerObj = new GameObject("EscapeContainer");
|
||||
_containerObj.transform.SetParent(transform, false);
|
||||
_containerObj.layer = 5;
|
||||
|
||||
var bgImage = _containerObj.AddComponent<Image>();
|
||||
// 고급스러운 다크톤 아크릴 감성
|
||||
bgImage.color = new Color(0.05f, 0.05f, 0.07f, 0.85f);
|
||||
bgImage.color = new Color(0.05f, 0.05f, 0.07f, 0.85f); // Dark tone acrylic style
|
||||
|
||||
var containerRect = _containerObj.GetComponent<RectTransform>();
|
||||
containerRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
containerRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
containerRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
containerRect.anchoredPosition = Vector2.zero; // 화면 중앙
|
||||
containerRect.anchoredPosition = Vector2.zero; // Screen center
|
||||
containerRect.sizeDelta = new Vector2(460, 160);
|
||||
|
||||
// 2. 텍스트 오브젝트 생성
|
||||
// 2. Create text object
|
||||
var textObj = new GameObject("EscapeText");
|
||||
textObj.transform.SetParent(_containerObj.transform, false);
|
||||
textObj.layer = 5;
|
||||
@@ -58,7 +57,7 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
_textComponent.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
_textComponent.richText = true;
|
||||
|
||||
// 게임의 기본 폰트 적용 (RDString.fontData.fontTMP)
|
||||
// Apply game's default font (RDString.fontData.fontTMP)
|
||||
if (RDString.fontData.fontTMP != null)
|
||||
_textComponent.font = RDString.fontData.fontTMP;
|
||||
|
||||
@@ -68,13 +67,13 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
textRect.offsetMin = new Vector2(10, 10);
|
||||
textRect.offsetMax = new Vector2(-10, -10);
|
||||
|
||||
// 초기 상태는 비활성화
|
||||
// Initial state disabled
|
||||
_containerObj.SetActive(false);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 렌더링이 더 이상 활성화되어 있지 않으면 자가 파괴
|
||||
// Destroy self if rendering is no longer active
|
||||
if (!RenderManager.IsActive)
|
||||
{
|
||||
Destroy(gameObject);
|
||||
@@ -93,10 +92,10 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
var elapsed = (float)_escapeStopwatch.Elapsed.TotalSeconds;
|
||||
var remaining = Mathf.Max(0f, 3f - elapsed);
|
||||
|
||||
// 남은 시간 텍스트 업데이트
|
||||
_textComponent.text = $"<color=#FF5252>탈출까지 {remaining:F1}초..</color>\n<size=40><color=#DDDDDD>Esc 키를 계속 누르고 계세요</color></size>";
|
||||
// Update remaining time text
|
||||
_textComponent.text = $"<color=#FF5252>Cancelling in {remaining:F1}s..</color>\n<size=40><color=#DDDDDD>Hold Esc to cancel render</color></size>";
|
||||
|
||||
// 마이크로 펄스 애니메이션 적용 (누르는 동안 컨테이너 전체 크기가 부드럽게 커짐)
|
||||
// Micro pulse animation (container smoothly scales up while holding)
|
||||
var scale = 1.0f + elapsed / 3.0f * 0.15f;
|
||||
_containerObj.transform.localScale = new Vector3(scale, scale, 1f);
|
||||
|
||||
@@ -104,10 +103,10 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
|
||||
_escapeStopwatch.Stop();
|
||||
_escapeStopwatch = null;
|
||||
_containerObj.transform.localScale = Vector3.one; // 스케일 초기화
|
||||
_containerObj.transform.localScale = Vector3.one; // Reset scale
|
||||
_containerObj.SetActive(false);
|
||||
|
||||
// 렌더링 취소 및 씬 이탈
|
||||
// Cancel rendering and exit scene
|
||||
if (RenderManager.Instance)
|
||||
RenderManager.Instance.CancelRender();
|
||||
}
|
||||
@@ -116,7 +115,7 @@ internal class EscapeHandlerUI : MonoBehaviour
|
||||
if (_escapeStopwatch == null) return;
|
||||
_escapeStopwatch.Stop();
|
||||
_escapeStopwatch = null;
|
||||
_containerObj.transform.localScale = Vector3.one; // 스케일 초기화
|
||||
_containerObj.transform.localScale = Vector3.one; // Reset scale
|
||||
_containerObj.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
+58
-58
@@ -96,11 +96,11 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 로딩 실패
|
||||
// Loading failed
|
||||
}
|
||||
}
|
||||
|
||||
// 폴백 처리
|
||||
// Fallback processing
|
||||
if (font == null)
|
||||
{
|
||||
try
|
||||
@@ -127,15 +127,15 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// UI 레이어(5) 설정
|
||||
// Set UI layer (5)
|
||||
gameObject.layer = 5;
|
||||
|
||||
// Canvas 설정
|
||||
// Canvas setup
|
||||
var canvas = gameObject.AddComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 32767; // 최상위
|
||||
canvas.sortingOrder = 32767; // Topmost
|
||||
|
||||
// 해상도 대응 캔버스 스케일러 설정
|
||||
// Responsive Canvas Scaler setup
|
||||
var scaler = gameObject.AddComponent<CanvasScaler>();
|
||||
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
|
||||
scaler.referenceResolution = new Vector2(1920, 1080);
|
||||
@@ -144,13 +144,13 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
|
||||
gameObject.AddComponent<GraphicRaycaster>();
|
||||
|
||||
// 1. 전체 화면 오버레이 배경 생성
|
||||
// 1. Create full screen overlay background
|
||||
var bgPanelObj = new GameObject("BackgroundPanel");
|
||||
bgPanelObj.transform.SetParent(transform, false);
|
||||
bgPanelObj.layer = 5;
|
||||
|
||||
var bgImage = bgPanelObj.AddComponent<Image>();
|
||||
bgImage.color = new Color(0f, 0f, 0f, 0.65f); // 어두운 투명 오버레이
|
||||
bgImage.color = new Color(0f, 0f, 0f, 0.65f); // Dark transparent overlay
|
||||
bgImage.raycastTarget = true;
|
||||
|
||||
var bgRect = bgPanelObj.GetComponent<RectTransform>();
|
||||
@@ -161,16 +161,16 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
|
||||
var font = GetNanumSquareNeoBdFontAsset();
|
||||
|
||||
// 2. 모달 컨테이너 생성 (다른 UI들과 디자인 일관성을 위해 동일한 아크릴 다크톤과 흰색 굵은 외곽선 적용)
|
||||
// 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); // 다른 UI의 배경 톤과 동일
|
||||
modalImage.color = new Color(0.08f, 0.08f, 0.1f, 0.88f);
|
||||
|
||||
var modalOutline = modalContainerObj.AddComponent<Outline>();
|
||||
modalOutline.effectColor = Color.white; // DebugMonitorUI와 일치하는 흰색 외곽선
|
||||
modalOutline.effectColor = Color.white;
|
||||
modalOutline.effectDistance = new Vector2(3.0f, -3.0f);
|
||||
|
||||
var modalRect = modalContainerObj.GetComponent<RectTransform>();
|
||||
@@ -179,13 +179,13 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
modalRect.pivot = new Vector2(0.5f, 0.5f);
|
||||
modalRect.sizeDelta = new Vector2(600, 320);
|
||||
|
||||
// 4. 타이틀 텍스트 생성
|
||||
// 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 라이브러리 설치 필요";
|
||||
titleText.text = "FFmpeg Library Installation Required";
|
||||
titleText.fontSize = 26;
|
||||
titleText.font = font;
|
||||
titleText.color = Color.white;
|
||||
@@ -198,23 +198,23 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
titleRect.anchoredPosition = new Vector2(0, -35);
|
||||
titleRect.sizeDelta = new Vector2(0, 40);
|
||||
|
||||
// 5. 본문 설명 텍스트 생성
|
||||
// 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();
|
||||
descStrBuilder.AppendLine("동영상을 렌더링하려면 FFmpeg 공유 라이브러리가 필요합니다.");
|
||||
descStrBuilder.AppendLine("FFmpeg shared libraries are required to render video.");
|
||||
if (Application.platform == RuntimePlatform.OSXPlayer)
|
||||
{
|
||||
descStrBuilder.AppendLine("OSX 플랫폼의 경우 신뢰 가능한 공개 빌드가 없어 수동으로 FFmpeg 8.1을 빌드하여야 합니다.");
|
||||
descStrBuilder.AppendLine("아래 버튼을 눌러 ffmpeg 공식 웹사이트를 열 수 있습니다.");
|
||||
descStrBuilder.AppendLine("For macOS, reliable public builds are unavailable, so FFmpeg 8.1 must be built manually.");
|
||||
descStrBuilder.AppendLine("Click the button below to open the official FFmpeg website.");
|
||||
}
|
||||
else
|
||||
{
|
||||
descStrBuilder.AppendLine("아래 버튼을 눌러 인터넷에서 자동으로 다운로드하여 설치합니다.");
|
||||
descStrBuilder.AppendLine("<color=#aaaaaa><size=13>(다운로드 크기: 약 70MB, UserLibs 폴더에 압축 해제됨)</size></color>");
|
||||
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>");
|
||||
}
|
||||
|
||||
descText.text = descStrBuilder.ToString();
|
||||
@@ -231,7 +231,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
descRect.anchoredPosition = new Vector2(0, -60);
|
||||
descRect.sizeDelta = new Vector2(-40, 100);
|
||||
|
||||
// 6. 버튼 컨테이너 생성
|
||||
// 6. Create button container
|
||||
_buttonContainerObj = new GameObject("ButtonContainer", typeof(RectTransform));
|
||||
_buttonContainerObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
_buttonContainerObj.layer = 5;
|
||||
@@ -243,7 +243,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
btnContainerRect.anchoredPosition = new Vector2(0, 35);
|
||||
btnContainerRect.sizeDelta = new Vector2(0, 50);
|
||||
|
||||
// 7. 다운로드 버튼 생성
|
||||
// 7. Create download button
|
||||
var downloadBtnObj = new GameObject("DownloadButton");
|
||||
downloadBtnObj.transform.SetParent(_buttonContainerObj.transform, false);
|
||||
downloadBtnObj.layer = 5;
|
||||
@@ -273,7 +273,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
downloadTextObj.layer = 5;
|
||||
|
||||
var downloadText = downloadTextObj.AddComponent<TextMeshProUGUI>();
|
||||
downloadText.text = Application.platform != RuntimePlatform.OSXPlayer ? "다운로드 및 설치" : "사이트 열기";
|
||||
downloadText.text = Application.platform != RuntimePlatform.OSXPlayer ? "Download & Install" : "Open Website";
|
||||
downloadText.fontSize = 20;
|
||||
downloadText.font = font;
|
||||
downloadText.color = Color.white;
|
||||
@@ -285,7 +285,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
downloadTextRect.offsetMin = Vector2.zero;
|
||||
downloadTextRect.offsetMax = Vector2.zero;
|
||||
|
||||
// 8. 취소 버튼 생성
|
||||
// 8. Create cancel button
|
||||
var cancelBtnObj = new GameObject("CancelButton");
|
||||
cancelBtnObj.transform.SetParent(_buttonContainerObj.transform, false);
|
||||
cancelBtnObj.layer = 5;
|
||||
@@ -310,7 +310,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
cancelTextObj.layer = 5;
|
||||
|
||||
var cancelText = cancelTextObj.AddComponent<TextMeshProUGUI>();
|
||||
cancelText.text = "취소";
|
||||
cancelText.text = "Cancel";
|
||||
cancelText.fontSize = 20;
|
||||
cancelText.font = font;
|
||||
cancelText.color = new Color(0.9f, 0.9f, 0.9f, 1f);
|
||||
@@ -322,18 +322,18 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
cancelTextRect.offsetMin = Vector2.zero;
|
||||
cancelTextRect.offsetMax = Vector2.zero;
|
||||
|
||||
// 9. 프로그레스 바 컨테이너 생성
|
||||
// 9. Create progress bar container
|
||||
_progressBarObj = new GameObject("ProgressBarContainer");
|
||||
_progressBarObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
_progressBarObj.layer = 5;
|
||||
_progressBarObj.SetActive(false);
|
||||
|
||||
var barBgImg = _progressBarObj.AddComponent<Image>();
|
||||
barBgImg.color = new Color(0.08f, 0.08f, 0.1f, 1.0f); // DebugMonitorUI의 BarBackgroundColor와 동일
|
||||
barBgImg.color = new Color(0.08f, 0.08f, 0.1f, 1.0f);
|
||||
|
||||
var barBgOutline = _progressBarObj.AddComponent<Outline>();
|
||||
barBgOutline.effectColor = Color.white; // DebugMonitorUI의 BarOutlineColor와 동일
|
||||
barBgOutline.effectDistance = new Vector2(3.0f, -3.0f); // DebugMonitorUI의 BarOutlineDistance와 동일
|
||||
barBgOutline.effectColor = Color.white;
|
||||
barBgOutline.effectDistance = new Vector2(3.0f, -3.0f);
|
||||
|
||||
var barRect = _progressBarObj.GetComponent<RectTransform>();
|
||||
barRect.anchorMin = new Vector2(0.5f, 0);
|
||||
@@ -342,28 +342,28 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
barRect.anchoredPosition = new Vector2(0, 75);
|
||||
barRect.sizeDelta = new Vector2(480, 24);
|
||||
|
||||
// 10. 프로그레스 바 채우기 이미지 생성
|
||||
// 10. Create progress bar fill image
|
||||
_progressBarFillObj = new GameObject("ProgressBarFill");
|
||||
_progressBarFillObj.transform.SetParent(_progressBarObj.transform, false);
|
||||
_progressBarFillObj.layer = 5;
|
||||
|
||||
var fillImg = _progressBarFillObj.AddComponent<Image>();
|
||||
fillImg.color = new Color(0.0f, 0.8f, 1.0f, 1.0f); // DebugMonitorUI의 BarFillColor와 동일
|
||||
fillImg.color = new Color(0.0f, 0.8f, 1.0f, 1.0f);
|
||||
|
||||
_fillRect = _progressBarFillObj.GetComponent<RectTransform>();
|
||||
_fillRect.anchorMin = new Vector2(0, 0);
|
||||
_fillRect.anchorMax = new Vector2(0, 1); // anchorMax.x가 동적으로 변경됨
|
||||
_fillRect.anchorMax = new Vector2(0, 1);
|
||||
_fillRect.pivot = new Vector2(0, 0.5f);
|
||||
_fillRect.anchoredPosition = Vector2.zero;
|
||||
_fillRect.sizeDelta = Vector2.zero;
|
||||
|
||||
// 11. 프로그레스 텍스트 생성 (진행률 표시)
|
||||
// 11. Create progress text
|
||||
var progressTextObj = new GameObject("ProgressBarText");
|
||||
progressTextObj.transform.SetParent(_progressBarObj.transform, false);
|
||||
progressTextObj.layer = 5;
|
||||
|
||||
_progressText = progressTextObj.AddComponent<TextMeshProUGUI>();
|
||||
_progressText.fontSize = 16; // DebugMonitorUI의 BarTextFontSize와 일치
|
||||
_progressText.fontSize = 16;
|
||||
_progressText.font = font;
|
||||
_progressText.color = Color.white;
|
||||
_progressText.alignment = TextAlignmentOptions.Center;
|
||||
@@ -378,14 +378,14 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
progressTextRect.offsetMin = Vector2.zero;
|
||||
progressTextRect.offsetMax = Vector2.zero;
|
||||
|
||||
// 12. 상태 텍스트 생성
|
||||
// 12. Create status text
|
||||
_statusTextObj = new GameObject("StatusText");
|
||||
_statusTextObj.transform.SetParent(modalContainerObj.transform, false);
|
||||
_statusTextObj.layer = 5;
|
||||
_statusTextObj.SetActive(false);
|
||||
|
||||
_statusText = _statusTextObj.AddComponent<TextMeshProUGUI>();
|
||||
_statusText.fontSize = 16; // DebugMonitorUI의 텍스트 크기와 일치
|
||||
_statusText.fontSize = 16;
|
||||
_statusText.font = font;
|
||||
_statusText.color = new Color(0.8f, 0.8f, 0.8f, 1f);
|
||||
_statusText.alignment = TextAlignmentOptions.Center;
|
||||
@@ -411,7 +411,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 백그라운드 스레드에서 메인 스레드로 넘겨진 작업 순차 실행
|
||||
// Execute queued actions on main thread
|
||||
while (_mainThreadQueue.TryDequeue(out var action))
|
||||
{
|
||||
action?.Invoke();
|
||||
@@ -428,20 +428,20 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
if (_isDownloading) return;
|
||||
_isDownloading = true;
|
||||
|
||||
// 버튼 숨기고 프로그레스 바 및 상태 텍스트 표시
|
||||
// Hide buttons and show progress bar & status text
|
||||
_buttonContainerObj.SetActive(false);
|
||||
_progressBarObj.SetActive(true);
|
||||
_statusTextObj.SetActive(true);
|
||||
|
||||
_cts = new System.Threading.CancellationTokenSource();
|
||||
|
||||
// 백그라운드 스레드에서 다운로드 시작
|
||||
// Start download in background thread
|
||||
Task.Run(async () =>
|
||||
{
|
||||
string tempZipPath = "";
|
||||
try
|
||||
{
|
||||
UpdateStatus("다운로드 시작하는 중...", new Color(0.8f, 0.8f, 0.8f));
|
||||
UpdateStatus("Starting download...", new Color(0.8f, 0.8f, 0.8f));
|
||||
UpdateProgress(0f, "0%");
|
||||
|
||||
var userLibsDir = MelonEnvironment.UserLibsDirectory;
|
||||
@@ -461,24 +461,24 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
var progressReporter = new Progress<float>(percent =>
|
||||
{
|
||||
UpdateProgress(percent, $"{percent * 100f:F1}%");
|
||||
UpdateStatus($"다운로드 중... ({(percent * 100f):F1}%)", new Color(0f, 0.8f, 1f));
|
||||
UpdateStatus($"Downloading... ({(percent * 100f):F1}%)", new Color(0f, 0.8f, 1f));
|
||||
});
|
||||
|
||||
await DownloadFileAsync(DownloadUrl, tempZipPath, progressReporter, _cts.Token);
|
||||
|
||||
// 다운로드 완료 후 압축 해제
|
||||
UpdateStatus("압축 해제 및 DLL 파일 복사 중...", new Color(0.9f, 0.9f, 0.2f));
|
||||
UpdateProgress(0.99f, "압축 해제 중...");
|
||||
// Extract after download complete
|
||||
UpdateStatus("Extracting and copying library files...", new Color(0.9f, 0.9f, 0.2f));
|
||||
UpdateProgress(0.99f, "Extracting...");
|
||||
|
||||
await ExtractDllsAsync(tempZipPath, userLibsDir);
|
||||
|
||||
// 완료 상태 업데이트
|
||||
UpdateStatus("FFmpeg 설치 완료!", new Color(0.2f, 0.9f, 0.2f));
|
||||
// Update completion status
|
||||
UpdateStatus("FFmpeg installation complete!", new Color(0.2f, 0.9f, 0.2f));
|
||||
UpdateProgress(1f, "100%");
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
// 메인 스레드에서 UI를 삭제
|
||||
// Destroy UI on main thread
|
||||
ExecuteOnMainThread(() =>
|
||||
{
|
||||
Destroy(gameObject);
|
||||
@@ -486,7 +486,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 취소 시 임시 파일 정리
|
||||
// Clean up temporary file on cancellation
|
||||
if (!string.IsNullOrEmpty(tempZipPath) && File.Exists(tempZipPath))
|
||||
{
|
||||
try { File.Delete(tempZipPath); }
|
||||
@@ -495,14 +495,14 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
UpdateStatus("다운로드가 취소되었습니다.", new Color(0.9f, 0.5f, 0.2f));
|
||||
UpdateStatus("Download was cancelled.", new Color(0.9f, 0.5f, 0.2f));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error($"FFmpeg 다운로드/설치 중 에러 발생: {ex}");
|
||||
UpdateStatus($"설치 실패: {ex.Message}", new Color(1f, 0.3f, 0.3f));
|
||||
Melon<RenderMod>.Logger.Error($"Error during FFmpeg download/installation: {ex}");
|
||||
UpdateStatus($"Installation failed: {ex.Message}", new Color(1f, 0.3f, 0.3f));
|
||||
|
||||
// 실패 시 버튼 재설정
|
||||
// Reset buttons on failure
|
||||
ExecuteOnMainThread(() =>
|
||||
{
|
||||
_isDownloading = false;
|
||||
@@ -510,7 +510,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
var downloadBtnText = _buttonContainerObj.transform.Find("DownloadButton/DownloadText")?.GetComponent<TextMeshProUGUI>();
|
||||
if (downloadBtnText)
|
||||
{
|
||||
downloadBtnText.text = "재시도 (Retry)";
|
||||
downloadBtnText.text = "Retry";
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -556,7 +556,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
private async Task DownloadFileAsync(string url, string destinationPath, IProgress<float> progress, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
using var client = new HttpClient();
|
||||
// User-Agent 헤더 추가하여 차단 방지
|
||||
// Add User-Agent header to prevent blocking
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ADOFAIRenderer/1.0");
|
||||
|
||||
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||
@@ -611,7 +611,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
}
|
||||
else
|
||||
{
|
||||
// 리눅스 (또는 기타 플랫폼) - tar.xz 해제
|
||||
// Linux (or other platforms) - extract tar.xz
|
||||
await Task.Run(() =>
|
||||
{
|
||||
var tempExtractDir = Path.Combine(outputDirectory, "ffmpeg_temp_extracted");
|
||||
@@ -640,11 +640,11 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
var error = process.StandardError.ReadToEnd();
|
||||
throw new Exception($"tar 압축 해제 실패 (ExitCode: {process.ExitCode}): {error}");
|
||||
throw new Exception($"tar extraction failed (ExitCode: {process.ExitCode}): {error}");
|
||||
}
|
||||
}
|
||||
|
||||
// 압축이 풀린 파일 중에서 .so 파일들을 찾아서 outputDirectory로 이동
|
||||
// Find .so files and copy to outputDirectory
|
||||
var soFiles = Directory.GetFiles(tempExtractDir, "*.so*", SearchOption.AllDirectories);
|
||||
foreach (var soFile in soFiles)
|
||||
{
|
||||
@@ -653,7 +653,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
File.Copy(soFile, targetPath, true);
|
||||
}
|
||||
|
||||
// 임시 디렉토리 정리
|
||||
// Clean up temporary directory
|
||||
try
|
||||
{
|
||||
Directory.Delete(tempExtractDir, true);
|
||||
@@ -675,7 +675,7 @@ internal class FFmpegDownloadUI : MonoBehaviour
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Warning($"임시 ZIP 파일 삭제 실패: {ex.Message}");
|
||||
Melon<RenderMod>.Logger.Warning($"Failed to delete temporary zip file: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+79
-82
@@ -62,34 +62,34 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
_videoEncodingConfigButton = _root.Q<Button>("VideoEncodingSettingsButton");
|
||||
if (_videoEncodingConfigButton != null)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] VideoEncodingSettingsButton 발견: pickingMode={_videoEncodingConfigButton.pickingMode}, enabledSelf={_videoEncodingConfigButton.enabledSelf}");
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] VideoEncodingSettingsButton found: pickingMode={_videoEncodingConfigButton.pickingMode}, enabledSelf={_videoEncodingConfigButton.enabledSelf}");
|
||||
_videoEncodingConfigButton.RegisterCallback<ClickEvent>(_ => OpenVideoEncodingConfig());
|
||||
}
|
||||
else
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error("Button 'VideoEncodingSettingsButton'을(를) 찾을 수 없습니다.");
|
||||
Melon<RenderMod>.Logger.Error("Button 'VideoEncodingSettingsButton' not found.");
|
||||
}
|
||||
|
||||
_audioEncodingConfigButton = _root.Q<Button>("AudioEncodingSettingsButton");
|
||||
if (_audioEncodingConfigButton != null)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] AudioEncodingSettingsButton 발견: pickingMode={_audioEncodingConfigButton.pickingMode}, enabledSelf={_audioEncodingConfigButton.enabledSelf}");
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] AudioEncodingSettingsButton found: pickingMode={_audioEncodingConfigButton.pickingMode}, enabledSelf={_audioEncodingConfigButton.enabledSelf}");
|
||||
_audioEncodingConfigButton.RegisterCallback<ClickEvent>(_ => OpenAudioEncodingConfig());
|
||||
}
|
||||
else
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error("Button 'AudioEncodingSettingsButton'을(를) 찾을 수 없습니다.");
|
||||
Melon<RenderMod>.Logger.Error("Button 'AudioEncodingSettingsButton' not found.");
|
||||
}
|
||||
|
||||
var presetSettingsButton = _root.Q<Button>("PresetSettingsButton");
|
||||
if (presetSettingsButton != null)
|
||||
{
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] PresetSettingsButton 발견: pickingMode={presetSettingsButton.pickingMode}, enabledSelf={presetSettingsButton.enabledSelf}");
|
||||
Melon<RenderMod>.Logger.Msg($"[UI] PresetSettingsButton found: pickingMode={presetSettingsButton.pickingMode}, enabledSelf={presetSettingsButton.enabledSelf}");
|
||||
presetSettingsButton.RegisterCallback<ClickEvent>(_ => OpenPresetConfig());
|
||||
}
|
||||
else
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error("Button 'PresetSettingsButton'을(를) 찾을 수 없습니다.");
|
||||
Melon<RenderMod>.Logger.Error("Button 'PresetSettingsButton' not found.");
|
||||
}
|
||||
|
||||
var bottomRow = CreateRow();
|
||||
@@ -99,11 +99,11 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
bottomRow.style.bottom = 0f;
|
||||
bottomRow.style.justifyContent = Justify.FlexEnd;
|
||||
|
||||
_advancedSettingsButton = new Button { name = "AdvancedSettingsButton", text = "고급 설정..." };
|
||||
_advancedSettingsButton = new Button { name = "AdvancedSettingsButton", text = "Advanced Settings..." };
|
||||
bottomRow.Add(_advancedSettingsButton);
|
||||
|
||||
(_root.childCount > 0 ? _root[0] : _root).Add(bottomRow);
|
||||
Melon<RenderMod>.Logger.Msg("[UI] AdvancedSettingsButton 동적 생성 완료.");
|
||||
Melon<RenderMod>.Logger.Msg("[UI] AdvancedSettingsButton dynamically created.");
|
||||
|
||||
_advancedSettingsButton.RegisterCallback<ClickEvent>(_ => OpenAdvancedConfig());
|
||||
|
||||
@@ -126,7 +126,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
}
|
||||
};
|
||||
|
||||
// 기존 UI와 동일한 폰트 적용
|
||||
// Apply same font as existing UI
|
||||
if (RenderMod.FontBundle)
|
||||
{
|
||||
try
|
||||
@@ -140,7 +140,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
_versionLabel.RegisterCallback<PointerUpLinkTagEvent>(OnLinkTagClicked);
|
||||
|
||||
(_root.childCount > 0 ? _root[0] : _root).Add(_versionLabel);
|
||||
Melon<RenderMod>.Logger.Msg("[UI] VersionLabel 동적 생성 완료.");
|
||||
Melon<RenderMod>.Logger.Msg("[UI] VersionLabel dynamically created.");
|
||||
}
|
||||
|
||||
private void OpenAdvancedConfig()
|
||||
@@ -176,9 +176,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
}
|
||||
};
|
||||
|
||||
// 1. 타이틀 로우
|
||||
// 1. Title Row
|
||||
var titleRow = CreateRow();
|
||||
var titleLabel = new Label("고급 설정")
|
||||
var titleLabel = new Label("Advanced Settings")
|
||||
{
|
||||
style =
|
||||
{
|
||||
@@ -189,9 +189,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
titleRow.Add(titleLabel);
|
||||
_advancedConfigContainer.Add(titleRow);
|
||||
|
||||
// 2. 확장자 로우
|
||||
// 2. Extension Row
|
||||
var fileExtensionRow = CreateRow();
|
||||
var fileExtensionLabel = CreateFormLabel("확장자");
|
||||
var fileExtensionLabel = CreateFormLabel("File Extension");
|
||||
var fileExtensionChoices = new List<string> { "mkv", "mp4", "mov", "webm", "avi" };
|
||||
var currentFileExt = string.IsNullOrWhiteSpace(tempConfig.FileExtension) ? "mkv" : tempConfig.FileExtension.TrimStart('.').ToLower();
|
||||
if (!fileExtensionChoices.Contains(currentFileExt))
|
||||
@@ -203,25 +203,25 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
fileExtensionRow.Add(fileExtensionDropdown);
|
||||
_advancedConfigContainer.Add(fileExtensionRow);
|
||||
|
||||
// 3. 오디오 처리 로우
|
||||
// 3. Audio Processing Row
|
||||
var processAudioRow = CreateRow();
|
||||
var processAudioLabel = CreateFormLabel("오디오 처리");
|
||||
var processAudioLabel = CreateFormLabel("Process Audio");
|
||||
var processAudioToggle = new Toggle { name = "AdvancedProcessAudioToggle", label = "", value = tempConfig.ProcessAudio };
|
||||
processAudioRow.Add(processAudioLabel);
|
||||
processAudioRow.Add(processAudioToggle);
|
||||
_advancedConfigContainer.Add(processAudioRow);
|
||||
|
||||
// 4. 논타일 모드 로우
|
||||
// 4. Non-Tile Mode Row
|
||||
var nonTileRow = CreateRow();
|
||||
var nonTileLabel = CreateFormLabel("논타일 모드");
|
||||
var nonTileLabel = CreateFormLabel("Non-Tile Mode");
|
||||
var nonTileToggle = new Toggle { name = "AdvancedNonTileToggle", label = "", value = tempConfig.NonTile };
|
||||
nonTileRow.Add(nonTileLabel);
|
||||
nonTileRow.Add(nonTileToggle);
|
||||
_advancedConfigContainer.Add(nonTileRow);
|
||||
|
||||
// 5. 랜덤 시드 로우
|
||||
// 5. Random Seed Row
|
||||
var randomSeedRow = CreateRow();
|
||||
var randomSeedLabel = CreateFormLabel("랜덤 시드 (입력 선택)");
|
||||
var randomSeedLabel = CreateFormLabel("Random Seed (Optional)");
|
||||
var randomSeedField = new TextField { name = "AdvancedRandomSeed", label = "", value = tempConfig.RandomSeed?.ToString() ?? string.Empty };
|
||||
|
||||
randomSeedField.RegisterValueChangedCallback(evt =>
|
||||
@@ -237,10 +237,10 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
randomSeedRow.Add(randomSeedField);
|
||||
_advancedConfigContainer.Add(randomSeedRow);
|
||||
|
||||
// 6. 제어 버튼 로우 (취소 / 저장)
|
||||
// 6. Control Button Row (Cancel / Save)
|
||||
var buttonRow = CreateRow();
|
||||
var cancelBtn = new Button { text = "취소" };
|
||||
var saveBtn = new Button { text = "저장" };
|
||||
var cancelBtn = new Button { text = "Cancel" };
|
||||
var saveBtn = new Button { text = "Save" };
|
||||
|
||||
buttonRow.Add(cancelBtn);
|
||||
buttonRow.Add(saveBtn);
|
||||
@@ -315,7 +315,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
_root.Remove(_videoEncodingConfigContainer);
|
||||
}
|
||||
|
||||
// 1. 전체 화면 컨테이너 생성 및 배경 적용
|
||||
// 1. Create full screen container and apply background
|
||||
_videoEncodingConfigContainer = new VisualElement
|
||||
{
|
||||
name = "VideoEncodingSettingsContainer",
|
||||
@@ -332,9 +332,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
}
|
||||
};
|
||||
|
||||
// 2. 타이틀 로우
|
||||
// 2. Title Row
|
||||
var titleRow = CreateRow();
|
||||
var titleLabel = new Label("비디오 인코딩 설정")
|
||||
var titleLabel = new Label("Video Encoding Settings")
|
||||
{
|
||||
style =
|
||||
{
|
||||
@@ -345,71 +345,71 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
titleRow.Add(titleLabel);
|
||||
_videoEncodingConfigContainer.Add(titleRow);
|
||||
|
||||
// 3. 코덱 로우
|
||||
// 3. Codec Row
|
||||
var codecRow = CreateRow();
|
||||
var codecLabel = CreateFormLabel("코덱");
|
||||
var codecLabel = CreateFormLabel("Codec");
|
||||
var codecChoices = new List<string>(Enum.GetNames(typeof(Codec)));
|
||||
var codecDropdown = new DropdownField(codecChoices, tempConfig.Codec.ToString()) { name = "VideoCodec" };
|
||||
codecRow.Add(codecLabel);
|
||||
codecRow.Add(codecDropdown);
|
||||
_videoEncodingConfigContainer.Add(codecRow);
|
||||
|
||||
// 4. 모드 로우
|
||||
// 4. Mode Row
|
||||
var modeRow = CreateRow();
|
||||
var modeLabel = CreateFormLabel("모드");
|
||||
var modeLabel = CreateFormLabel("Mode");
|
||||
var modeChoices = new List<string>(Enum.GetNames(typeof(RateControlMode)));
|
||||
var modeDropdown = new DropdownField(modeChoices, tempConfig.RateControlMode.ToString()) { name = "VideoRateControlMode" };
|
||||
modeRow.Add(modeLabel);
|
||||
modeRow.Add(modeDropdown);
|
||||
_videoEncodingConfigContainer.Add(modeRow);
|
||||
|
||||
// 5. 비트레이트 로우
|
||||
// 5. Bitrate Row
|
||||
var bitrateRow = CreateRow();
|
||||
var bitrateLabel = CreateFormLabel("비트레이트(kbps)");
|
||||
var bitrateLabel = CreateFormLabel("Bitrate (kbps)");
|
||||
var bitrateField = new IntegerField { name = "VideoBitrate", label = "", value = tempConfig.Bitrate };
|
||||
bitrateRow.Add(bitrateLabel);
|
||||
bitrateRow.Add(bitrateField);
|
||||
_videoEncodingConfigContainer.Add(bitrateRow);
|
||||
|
||||
// 5.5. 최대 비트레이트 로우 (VBR 전용)
|
||||
// 5.5. Max Bitrate Row (VBR only)
|
||||
var maxBitrateRow = CreateRow();
|
||||
var maxBitrateLabel = CreateFormLabel("최대 비트레이트(kbps)");
|
||||
var maxBitrateLabel = CreateFormLabel("Max Bitrate (kbps)");
|
||||
var maxBitrateField = new IntegerField { name = "VideoMaxBitrate", label = "", value = tempConfig.MaxBitrate };
|
||||
maxBitrateRow.Add(maxBitrateLabel);
|
||||
maxBitrateRow.Add(maxBitrateField);
|
||||
_videoEncodingConfigContainer.Add(maxBitrateRow);
|
||||
|
||||
// 6. QP 로우
|
||||
// 6. QP Row
|
||||
var qpRow = CreateRow();
|
||||
var qpLabel = CreateFormLabel("품질 (QP)");
|
||||
var qpLabel = CreateFormLabel("Quality (QP)");
|
||||
var qpField = new IntegerField { name = "VideoQP", label = "", value = tempConfig.QP };
|
||||
qpRow.Add(qpLabel);
|
||||
qpRow.Add(qpField);
|
||||
_videoEncodingConfigContainer.Add(qpRow);
|
||||
|
||||
// 6.5. 키프레임 간격 로우 (초 단위)
|
||||
// 6.5. Keyframe Interval Row (seconds)
|
||||
var keyframeRow = CreateRow();
|
||||
var keyframeLabel = CreateFormLabel("키프레임 간격(초)");
|
||||
var keyframeLabel = CreateFormLabel("Keyframe Interval (s)");
|
||||
var keyframeField = new DoubleField { name = "VideoKeyframeInterval", label = "", value = tempConfig.KeyframeInterval };
|
||||
keyframeRow.Add(keyframeLabel);
|
||||
keyframeRow.Add(keyframeField);
|
||||
_videoEncodingConfigContainer.Add(keyframeRow);
|
||||
|
||||
// 6.75. 강제 소프트웨어 인코더 로우 (라벨 + 토글)
|
||||
// 6.75. Force Software Encoder Row (Label + Toggle)
|
||||
var forceSoftwareRow = CreateRow();
|
||||
var forceSoftwareLabel = CreateFormLabel("소프트웨어 인코더");
|
||||
var forceSoftwareLabel = CreateFormLabel("Software Encoder");
|
||||
var forceSoftwareToggle = new Toggle { name = "VideoForceSoftwareEncoderToggle", label = "", value = tempConfig.ForceSoftwareEncoder };
|
||||
forceSoftwareRow.Add(forceSoftwareLabel);
|
||||
forceSoftwareRow.Add(forceSoftwareToggle);
|
||||
_videoEncodingConfigContainer.Add(forceSoftwareRow);
|
||||
|
||||
// 7. QP = 0 (무손실) 경고 라벨 로우 생성
|
||||
// 7. QP = 0 (Lossless) Warning Label Row
|
||||
var warningRow = CreateRow();
|
||||
warningRow.style.height = StyleKeyword.Auto;
|
||||
warningRow.style.maxHeight = StyleKeyword.Null;
|
||||
warningRow.style.minHeight = StyleKeyword.Null;
|
||||
|
||||
var warningLabel = new Label("주의: QP를 0으로 설정하면 무손실 인코딩이 적용되어 용량이 매우 커질 수 있습니다.")
|
||||
var warningLabel = new Label("Warning: Setting QP to 0 applies lossless encoding and may result in very large file sizes.")
|
||||
{
|
||||
style =
|
||||
{
|
||||
@@ -441,10 +441,10 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
: DisplayStyle.None;
|
||||
});
|
||||
|
||||
// 8. 제어 버튼 로우 (취소 / 저장)
|
||||
// 8. Control Button Row (Cancel / Save)
|
||||
var buttonRow = CreateRow();
|
||||
var cancelBtn = new Button { text = "취소" };
|
||||
var saveBtn = new Button { text = "저장" };
|
||||
var cancelBtn = new Button { text = "Cancel" };
|
||||
var saveBtn = new Button { text = "Save" };
|
||||
|
||||
buttonRow.Add(cancelBtn);
|
||||
buttonRow.Add(saveBtn);
|
||||
@@ -489,11 +489,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
|
||||
_root.Add(_videoEncodingConfigContainer);
|
||||
|
||||
// 화면 전환 활성화
|
||||
ToggleScreens(true);
|
||||
return;
|
||||
|
||||
// 화면 전환 제어
|
||||
void ToggleScreens(bool showEncoding)
|
||||
{
|
||||
if (_root.childCount > 0)
|
||||
@@ -503,7 +501,6 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
_videoEncodingConfigContainer.style.display = showEncoding ? DisplayStyle.Flex : DisplayStyle.None;
|
||||
}
|
||||
|
||||
// 가시성 필터링 업데이트 (행 단위로 보임/숨김 제어)
|
||||
void UpdateVisibility(string selectedModeStr)
|
||||
{
|
||||
if (!Enum.TryParse<RateControlMode>(selectedModeStr, out var mode)) return;
|
||||
@@ -547,9 +544,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
}
|
||||
};
|
||||
|
||||
// 1. 타이틀 로우
|
||||
// 1. Title Row
|
||||
var titleRow = CreateRow();
|
||||
var titleLabel = new Label("오디오 인코딩 설정")
|
||||
var titleLabel = new Label("Audio Encoding Settings")
|
||||
{
|
||||
style =
|
||||
{
|
||||
@@ -560,17 +557,17 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
titleRow.Add(titleLabel);
|
||||
_audioEncodingConfigContainer.Add(titleRow);
|
||||
|
||||
// 2. 오디오 렌더링 활성화 로우 (라벨 + 토글)
|
||||
// 2. Enable Audio Rendering Row (Label + Toggle)
|
||||
var renderAudioRow = CreateRow();
|
||||
var renderAudioLabel = CreateFormLabel("오디오 렌더링 활성화");
|
||||
var renderAudioLabel = CreateFormLabel("Enable Audio Rendering");
|
||||
var renderAudioToggle = new Toggle { name = "AudioRenderAudioToggle", label = "", value = tempAudioConfig.RenderAudio };
|
||||
renderAudioRow.Add(renderAudioLabel);
|
||||
renderAudioRow.Add(renderAudioToggle);
|
||||
_audioEncodingConfigContainer.Add(renderAudioRow);
|
||||
|
||||
// 3. 샘플 레이트 로우
|
||||
// 3. Sample Rate Row
|
||||
var sampleRateRow = CreateRow();
|
||||
var sampleRateLabel = CreateFormLabel("샘플 레이트(Hz)");
|
||||
var sampleRateLabel = CreateFormLabel("Sample Rate (Hz)");
|
||||
var isOpus = config.VideoConfig.Codec is Codec.AV1 or Codec.VP9 or Codec.VVC;
|
||||
|
||||
List<string> sampleRateChoices;
|
||||
@@ -599,9 +596,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
sampleRateRow.Add(sampleRateDropdown);
|
||||
_audioEncodingConfigContainer.Add(sampleRateRow);
|
||||
|
||||
// 4. 채널 로우
|
||||
// 4. Channels Row
|
||||
var channelsRow = CreateRow();
|
||||
var channelsLabel = CreateFormLabel("오디오 채널");
|
||||
var channelsLabel = CreateFormLabel("Audio Channels");
|
||||
var channelsDropdown = new DropdownField(
|
||||
new List<string> { "1 (Mono)", "2 (Stereo)" },
|
||||
tempAudioConfig.AudioChannels == 1 ? "1 (Mono)" : "2 (Stereo)"
|
||||
@@ -610,9 +607,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
channelsRow.Add(channelsDropdown);
|
||||
_audioEncodingConfigContainer.Add(channelsRow);
|
||||
|
||||
// 5. 비트레이트 로우 (kbps 단위 입력)
|
||||
// 5. Bitrate Row (input in kbps)
|
||||
var bitrateRow = CreateRow();
|
||||
var bitrateLabel = CreateFormLabel("오디오 비트레이트(kbps)");
|
||||
var bitrateLabel = CreateFormLabel("Audio Bitrate (kbps)");
|
||||
var bitrateField = new IntegerField { name = "AudioBitrateKbps", label = "", value = tempAudioConfig.AudioBitrate / 1000 };
|
||||
bitrateRow.Add(bitrateLabel);
|
||||
bitrateRow.Add(bitrateField);
|
||||
@@ -622,14 +619,14 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
audioValidator.AddLimits("AudioBitrateKbps", new PositiveOnlyIntegerLimit(), new RangeIntegerLimit(32, 1024));
|
||||
audioValidator.SetupValidation();
|
||||
|
||||
// 가시성 업데이트 (오디오 렌더링 비활성화 시 하위 설정 숨김)
|
||||
// Update visibility (hide sub-settings when audio rendering is disabled)
|
||||
renderAudioToggle.RegisterValueChangedCallback(evt => UpdateAudioVisibility(evt.newValue));
|
||||
UpdateAudioVisibility(tempAudioConfig.RenderAudio);
|
||||
|
||||
// 6. 제어 버튼 로우 (취소 / 저장)
|
||||
// 6. Control Button Row (Cancel / Save)
|
||||
var buttonRow = CreateRow();
|
||||
var cancelBtn = new Button { text = "취소" };
|
||||
var saveBtn = new Button { text = "저장" };
|
||||
var cancelBtn = new Button { text = "Cancel" };
|
||||
var saveBtn = new Button { text = "Save" };
|
||||
|
||||
buttonRow.Add(cancelBtn);
|
||||
buttonRow.Add(saveBtn);
|
||||
@@ -686,7 +683,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
{
|
||||
if (!ValidateInputs())
|
||||
{
|
||||
Melon<RenderMod>.Logger.Error("필수 입력 값이 비어 있거나 올바르지 않습니다. 모든 설정을 입력해 주세요.");
|
||||
Melon<RenderMod>.Logger.Error("Required input fields are empty or invalid. Please fill in all settings.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -788,7 +785,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
titleRow.style.height = StyleKeyword.Auto;
|
||||
titleRow.style.minHeight = StyleKeyword.Null;
|
||||
titleRow.style.maxHeight = StyleKeyword.Null;
|
||||
var title = new Label("프리셋 설정")
|
||||
var title = new Label("Preset Settings")
|
||||
{
|
||||
style =
|
||||
{
|
||||
@@ -877,7 +874,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
var saveRow = CreateRow();
|
||||
saveRow.style.marginBottom = 20;
|
||||
|
||||
var nameLabelLabel = CreateFormLabel("새 프리셋 이름");
|
||||
var nameLabelLabel = CreateFormLabel("New Preset Name");
|
||||
nameLabelLabel.style.marginRight = 10;
|
||||
|
||||
var nameField = new TextField
|
||||
@@ -890,7 +887,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
}
|
||||
};
|
||||
|
||||
// 기존 폼 입력 필드 스타일과 맞춤
|
||||
// Match existing form input field style
|
||||
var textInput = nameField.Q("unity-text-input");
|
||||
if (textInput != null)
|
||||
{
|
||||
@@ -919,7 +916,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
nameField.style.borderBottomRightRadius = 6f;
|
||||
}
|
||||
|
||||
var saveBtn = new Button { text = "저장" };
|
||||
var saveBtn = new Button { text = "Save" };
|
||||
|
||||
saveBtn.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
@@ -927,9 +924,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
if (string.IsNullOrWhiteSpace(presetName))
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
"저장 실패",
|
||||
"프리셋 이름을 입력해 주세요.",
|
||||
new DialogButton("확인", () => {})
|
||||
"Save Failed",
|
||||
"Please enter a preset name.",
|
||||
new DialogButton("OK", () => {})
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -937,9 +934,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
if (!ValidateInputs())
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
"저장 실패",
|
||||
"필수 입력 값이 비어 있거나 올바르지 않아 프리셋을 저장할 수 없습니다.",
|
||||
new DialogButton("확인", () => {})
|
||||
"Save Failed",
|
||||
"Cannot save preset because required input values are empty or invalid.",
|
||||
new DialogButton("OK", () => {})
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -973,9 +970,9 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
catch (Exception ex)
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog(
|
||||
"저장 실패",
|
||||
$"프리셋 저장 중 오류가 발생했습니다: {ex.Message}",
|
||||
new DialogButton("확인", () => {})
|
||||
"Save Failed",
|
||||
$"An error occurred while saving the preset: {ex.Message}",
|
||||
new DialogButton("OK", () => {})
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -988,7 +985,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
// Bottom controls: Close Button
|
||||
var closeRow = CreateRow();
|
||||
|
||||
var closeBtn = new Button { text = "닫기" };
|
||||
var closeBtn = new Button { text = "Close" };
|
||||
|
||||
closeBtn.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
@@ -1015,7 +1012,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
emptyRow.style.minHeight = StyleKeyword.Null;
|
||||
emptyRow.style.maxHeight = StyleKeyword.Null;
|
||||
|
||||
var emptyLabel = new Label("저장된 프리셋이 없습니다.") { style = { color = new StyleColor(Color.gray), unityTextAlign = TextAnchor.MiddleCenter, marginTop = 80, fontSize = 20 } };
|
||||
var emptyLabel = new Label("No saved presets.") { style = { color = new StyleColor(Color.gray), unityTextAlign = TextAnchor.MiddleCenter, marginTop = 80, fontSize = 20 } };
|
||||
emptyRow.Add(emptyLabel);
|
||||
scrollView.Add(emptyRow);
|
||||
}
|
||||
@@ -1045,7 +1042,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
|
||||
var loadBtn = new Button
|
||||
{
|
||||
text = "불러오기",
|
||||
text = "Load",
|
||||
style =
|
||||
{
|
||||
marginRight = 10,
|
||||
@@ -1085,7 +1082,7 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
|
||||
var deleteBtn = new Button
|
||||
{
|
||||
text = "삭제",
|
||||
text = "Delete",
|
||||
style =
|
||||
{
|
||||
width = 120f,
|
||||
@@ -1116,11 +1113,11 @@ internal class RenderConfigUIManager : MonoBehaviour
|
||||
|
||||
deleteBtn.RegisterCallback<ClickEvent>(_ =>
|
||||
{
|
||||
CommonWarningDialogUI.ShowDialog("프리셋 삭제", $"'{preset.Name}' 프리셋을 정말 삭제하시겠습니까?", new DialogButton("예", () =>
|
||||
CommonWarningDialogUI.ShowDialog("Delete Preset", $"Are you sure you want to delete the preset '{preset.Name}'?", new DialogButton("Yes", () =>
|
||||
{
|
||||
PresetManager.DeletePreset(preset.Name);
|
||||
RefreshPresets();
|
||||
}), new DialogButton("아니오", () => { }));
|
||||
}), new DialogButton("No", () => { }));
|
||||
});
|
||||
|
||||
btnContainer.Add(loadBtn);
|
||||
|
||||
Reference in new issue
Block a user