#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
///
/// 프로그레스 바 컴포넌트.
/// Unity ProgressBar를 래핑하여 커스텀 스타일을 적용합니다.
/// 작업의 진행 상황을 시각적으로 표시합니다.
///
///
/// ProgressBar(진행률 표시줄)란?
///
/// ProgressBar는 작업의 완료 정도를 시각적으로 표시하는 UI 컨트롤입니다.
/// 파일 다운로드, 로딩, 설치 진행률 등 사용자에게 대기 시간과 완료 상태를 알려줍니다.
///
///
/// 주요 속성:
///
/// - Value - 현재 진행 값
/// - MinValue - 최소값 (보통 0)
/// - MaxValue - 최대값 (보통 100)
/// - ShowValue - 값 텍스트 표시 여부
/// - ShowPercentage - 퍼센트로 표시 (true) 또는 값/최대값으로 표시 (false)
/// - IsIndeterminate - 불확정 상태 (진행률을 알 수 없을 때 애니메이션)
/// - Variant - 스타일 변형 (Default, Success, Warning, Error)
///
///
/// Variant 스타일:
///
/// - Default - 기본 파란색 (일반 진행)
/// - Success - 녹색 (완료, 성공)
/// - Warning - 주황색 (주의 필요)
/// - Error - 빨간색 (오류, 실패)
///
///
/// 불확정 상태(Indeterminate):
///
/// 작업 완료 시점을 알 수 없을 때 사용합니다 (예: 서버 응답 대기).
/// 바가 좌우로 움직이는 애니메이션으로 "작업 중"임을 표시합니다.
///
///
/// 실제 활용 예시:
///
/// - 파일 다운로드/업로드 진행률
/// - 게임 로딩 화면
/// - 설치/업데이트 진행 상태
/// - 데이터 처리 진행률
/// - 퀘스트/미션 달성도
///
///
///
/// C# 코드에서 사용:
///
/// // 다운로드 진행률 표시
/// var downloadProgress = new UTKProgressBar("다운로드 중...", 0, 100);
/// downloadProgress.ShowPercentage = true;
///
/// // 비동기 다운로드 시뮬레이션
/// async UniTask DownloadFile()
/// {
/// for (int i = 0; i <= 100; i++)
/// {
/// downloadProgress.Value = i;
/// await UniTask.Delay(50);
/// }
/// downloadProgress.Variant = UTKProgressBar.ProgressBarVariant.Success;
/// }
///
/// // 불확정 상태 (서버 응답 대기)
/// var loadingBar = new UTKProgressBar();
/// loadingBar.IsIndeterminate = true; // 무한 애니메이션
///
/// // 상태별 색상 변경
/// progressBar.Variant = UTKProgressBar.ProgressBarVariant.Warning; // 주의
/// progressBar.Variant = UTKProgressBar.ProgressBarVariant.Error; // 실패
///
/// // 값/최대값 형식 (예: 50/100)
/// var itemProgress = new UTKProgressBar("수집한 아이템", 0, 100);
/// itemProgress.ShowPercentage = false; // "50/100" 형식으로 표시
/// itemProgress.Value = 50;
///
/// UXML에서 사용:
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
///
[UxmlElement]
public partial class UTKProgressBar : ProgressBar, IDisposable
{
#region Constants
private const string USS_PATH = "UIToolkit/Slider/UTKProgressBar";
#endregion
#region Fields
private bool _disposed;
private bool _showValue = true;
private bool _showPercentage = true;
private bool _isIndeterminate;
private ProgressBarVariant _variant = ProgressBarVariant.Default;
private string _baseTitle = "";
#endregion
#region Properties
/// 현재 값
public float Value
{
get => value;
set => SetValue(value);
}
/// 최소값
public float MinValue
{
get => lowValue;
set
{
lowValue = value;
UpdateValueLabel();
}
}
/// 최대값
public float MaxValue
{
get => highValue;
set
{
highValue = value;
UpdateValueLabel();
}
}
/// 값 표시 여부
[UxmlAttribute("show-value")]
public bool ShowValue
{
get => _showValue;
set
{
_showValue = value;
UpdateValueLabel();
}
}
/// 퍼센트로 표시 여부
[UxmlAttribute("show-percentage")]
public bool ShowPercentage
{
get => _showPercentage;
set
{
_showPercentage = value;
UpdateValueLabel();
}
}
/// 불확정 상태 (애니메이션)
[UxmlAttribute("is-indeterminate")]
public bool IsIndeterminate
{
get => _isIndeterminate;
set
{
_isIndeterminate = value;
EnableInClassList("utk-progress--indeterminate", value);
UpdateValueLabel();
}
}
/// 스타일 변형
[UxmlAttribute("variant")]
public ProgressBarVariant Variant
{
get => _variant;
set
{
_variant = value;
UpdateVariant();
}
}
#endregion
#region Enums
public enum ProgressBarVariant
{
Default,
Success,
Warning,
Error
}
#endregion
#region Constructor
public UTKProgressBar() : base()
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
var uss = Resources.Load(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
SetupStyles();
SubscribeToThemeChanges();
// UXML에서 value가 설정된 후 title 갱신
RegisterCallback(OnAttachToPanel);
}
private void OnAttachToPanel(AttachToPanelEvent evt)
{
UnregisterCallback(OnAttachToPanel);
UpdateValueLabel();
}
public UTKProgressBar(string text, float value = 0f, float maxValue = 100f) : this()
{
title = text;
highValue = maxValue;
SetValue(value);
}
#endregion
#region Setup
private void SetupStyles()
{
AddToClassList("utk-progress");
UpdateVariant();
UpdateValueLabel();
}
private void SubscribeToThemeChanges()
{
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
RegisterCallback(OnAttachToPanelForTheme);
RegisterCallback(OnDetachFromPanelForTheme);
}
private void OnAttachToPanelForTheme(AttachToPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UTKThemeManager.Instance.OnThemeChanged += OnThemeChanged;
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
private void OnDetachFromPanelForTheme(DetachFromPanelEvent evt)
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
}
private void OnThemeChanged(UTKTheme theme)
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
#endregion
#region Methods
///
/// 값 설정
///
public void SetValue(float newValue)
{
value = Mathf.Clamp(newValue, lowValue, highValue);
UpdateValueLabel();
}
private void UpdateValueLabel()
{
if (_isIndeterminate || !_showValue)
{
title = _baseTitle;
return;
}
if (_showPercentage)
{
float range = highValue - lowValue;
float percent = range > 0 ? (value - lowValue) / range * 100 : 0;
title = $"{percent:F0}%";
}
else
{
title = $"{value:F0}/{highValue:F0}";
}
}
private void UpdateVariant()
{
RemoveFromClassList("utk-progress--default");
RemoveFromClassList("utk-progress--success");
RemoveFromClassList("utk-progress--warning");
RemoveFromClassList("utk-progress--error");
var variantClass = _variant switch
{
ProgressBarVariant.Success => "utk-progress--success",
ProgressBarVariant.Warning => "utk-progress--warning",
ProgressBarVariant.Error => "utk-progress--error",
_ => "utk-progress--default"
};
AddToClassList(variantClass);
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
_disposed = true;
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
UnregisterCallback(OnAttachToPanelForTheme);
UnregisterCallback(OnDetachFromPanelForTheme);
}
#endregion
}
}