Files
XRLib/Assets/Scripts/UVC/UIToolkit/Slider/UTKProgressBar.cs
2026-01-20 20:18:47 +09:00

258 lines
7.1 KiB
C#

#nullable enable
using System;
using UnityEngine;
using UnityEngine.UIElements;
namespace UVC.UIToolkit
{
/// <summary>
/// 프로그레스 바 컴포넌트.
/// Unity ProgressBar를 래핑하여 커스텀 스타일을 적용합니다.
/// </summary>
/// <example>
/// <para><b>C# 코드에서 사용:</b></para>
/// <code>
/// // 기본 프로그레스 바
/// var progressBar = new UTKProgressBar();
/// progressBar.title = "다운로드 중...";
/// progressBar.MinValue = 0;
/// progressBar.MaxValue = 100;
/// progressBar.Value = 50;
///
/// // 값 표시 설정
/// progressBar.ShowValue = true;
/// progressBar.ShowPercentage = true;
///
/// // 무한 로딩 (불확정 상태)
/// progressBar.IsIndeterminate = true;
///
/// // 변형 스타일
/// progressBar.Variant = UTKProgressBar.ProgressBarVariant.Success;
/// </code>
/// <para><b>UXML에서 사용:</b></para>
/// <code>
/// <ui:UXML xmlns:utk="UVC.UIToolkit">
/// <!-- 기본 프로그레스 바 -->
/// <utk:UTKProgressBar title="진행률" low-value="0" high-value="100" value="30" />
///
/// <!-- 퍼센트 표시 -->
/// <utk:UTKProgressBar ShowPercentage="true" value="75" />
///
/// <!-- 성공 스타일 -->
/// <utk:UTKProgressBar Variant="Success" value="100" />
/// </ui:UXML>
/// </code>
/// </example>
[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;
#endregion
#region Properties
/// <summary>현재 값</summary>
public float Value
{
get => value;
set => SetValue(value);
}
/// <summary>최소값</summary>
public float MinValue
{
get => lowValue;
set
{
lowValue = value;
UpdateValueLabel();
}
}
/// <summary>최대값</summary>
public float MaxValue
{
get => highValue;
set
{
highValue = value;
UpdateValueLabel();
}
}
/// <summary>값 표시 여부</summary>
[UxmlAttribute("show-value")]
public bool ShowValue
{
get => _showValue;
set
{
_showValue = value;
UpdateValueLabel();
}
}
/// <summary>퍼센트로 표시 여부</summary>
[UxmlAttribute("show-percentage")]
public bool ShowPercentage
{
get => _showPercentage;
set
{
_showPercentage = value;
UpdateValueLabel();
}
}
/// <summary>불확정 상태 (애니메이션)</summary>
[UxmlAttribute("is-indeterminate")]
public bool IsIndeterminate
{
get => _isIndeterminate;
set
{
_isIndeterminate = value;
EnableInClassList("utk-progress--indeterminate", value);
UpdateValueLabel();
}
}
/// <summary>스타일 변형</summary>
[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<StyleSheet>(USS_PATH);
if (uss != null)
{
styleSheets.Add(uss);
}
SetupStyles();
SubscribeToThemeChanges();
}
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<DetachFromPanelEvent>(_ =>
{
UTKThemeManager.Instance.OnThemeChanged -= OnThemeChanged;
});
}
private void OnThemeChanged(UTKTheme theme)
{
UTKThemeManager.Instance.ApplyThemeToElement(this);
}
#endregion
#region Methods
/// <summary>
/// 값 설정
/// </summary>
public void SetValue(float newValue)
{
value = Mathf.Clamp(newValue, lowValue, highValue);
UpdateValueLabel();
}
private void UpdateValueLabel()
{
if (_isIndeterminate || !_showValue)
{
title = title?.Split(' ')[0] ?? "";
return;
}
string baseTitle = title?.Split(' ')[0] ?? "";
if (_showPercentage)
{
float range = highValue - lowValue;
float percent = range > 0 ? (value - lowValue) / range * 100 : 0;
title = string.IsNullOrEmpty(baseTitle) ? $"{percent:F0}%" : $"{baseTitle} {percent:F0}%";
}
else
{
title = string.IsNullOrEmpty(baseTitle) ? $"{value:F0}/{highValue:F0}" : $"{baseTitle} {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;
}
#endregion
}
}