#nullable enable using System; using System.Threading; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.UIElements; namespace UVC.UIToolkit { /// /// 아이콘 토글 버튼 컴포넌트. /// IsOn 상태에 따라 OnIcon/OffIcon 이미지가 전환됩니다. /// Material Icons(1순위)와 Image Icons(2순위)를 자동 감지하여 적용합니다. /// /// /// C# 코드에서 사용: /// /// // Material Icon 사용 (자동 감지) /// var btn = new UTKImageToggleButton(); /// btn.OnIcon = UTKMaterialIcons.Visibility; /// btn.OffIcon = UTKMaterialIcons.VisibilityOff; /// btn.OnValueChanged += (isOn) => Debug.Log($"상태: {isOn}"); /// /// // Image Icon 사용 (자동 감지) /// var btn2 = new UTKImageToggleButton(UTKImageIcons.IconEye, UTKImageIcons.IconSetting22); /// /// // IsEnabled vs IsInteractive /// btn.IsEnabled = false; // 시각적 비활성화 + 모든 변경 불가 /// btn.IsInteractive = false; // 사용자 입력만 차단, 시각적 활성화 유지 /// /// // 프로그래밍 방식으로 상태 변경 (notify 여부 선택) /// btn.SetOn(true, notify: false); /// /// UXML에서 사용: /// /// /// /// /// /// /// /// /// /// /// /// /// [UxmlElement] public partial class UTKImageToggleButton : VisualElement, IDisposable { #region Constants private const string UXML_PATH = "UIToolkit/Button/UTKImageToggleButton"; private const string USS_PATH = "UIToolkit/Button/UTKImageToggleButtonUss"; private const int DEFAULT_ICON_SIZE = 24; #endregion #region Fields private bool _disposed; private bool _isOn; private bool _isEnabled = true; private bool _isInteractive = true; private string _onIcon = ""; private string _offIcon = ""; private int _iconSize = DEFAULT_ICON_SIZE; private Vector2Int _size = Vector2Int.zero; // zero = 미설정 (USS 기본값 사용) // 아이콘 표시용 요소 (캐싱) private Label? _materialIconLabel; private VisualElement? _imageIconElement; // 현재 표시 중인 아이콘 타입 private enum IconDisplayType { None, Material, Image } private IconDisplayType _currentDisplayType = IconDisplayType.None; #endregion #region Events /// 상태 변경 이벤트 public event Action? OnValueChanged; #endregion #region Properties /// /// On 상태일 때 표시할 아이콘. /// Material Icon 이름(예: "visibility") 또는 Image Icon 경로(예: UTKImageIcons.IconEye)를 지정합니다. /// Material Icons를 1순위로 자동 감지합니다. /// [UxmlAttribute("on-icon")] public string OnIcon { get => _onIcon; set { _onIcon = value; UpdateIconDisplay(); } } /// /// Off 상태일 때 표시할 아이콘. /// Material Icon 이름(예: "visibility_off") 또는 Image Icon 경로를 지정합니다. /// [UxmlAttribute("off-icon")] public string OffIcon { get => _offIcon; set { _offIcon = value; UpdateIconDisplay(); } } /// /// 버튼 크기 (픽셀). Vector2Int.zero이면 USS 기본값(var(--size-icon-btn))을 사용합니다. /// [UxmlAttribute("size")] public Vector2Int Size { get => _size; set { _size = value; if (_size == Vector2Int.zero) { style.width = StyleKeyword.Null; style.height = StyleKeyword.Null; } else { style.width = _size.x; style.height = _size.y; } } } /// 아이콘 크기 (픽셀) [UxmlAttribute("icon-size")] public int IconSize { get => _iconSize; set { _iconSize = value; ApplyIconSize(); } } /// 토글 상태 [UxmlAttribute("is-on")] public bool IsOn { get => _isOn; set => SetOn(value, notify: true); } /// 활성화 상태. false이면 시각적 비활성화 + 모든 변경 불가. [UxmlAttribute("is-enabled")] public bool IsEnabled { get => _isEnabled; set { _isEnabled = value; SetEnabled(value); EnableInClassList("utk-image-toggle-btn--disabled", !value); } } /// /// 상호작용 가능 여부. false이면 마우스/키보드 입력을 무시하지만 /// 프로그래밍 방식으로는 값 변경 가능. 시각적으로는 활성화 상태 유지. /// [UxmlAttribute("is-interactive")] public bool IsInteractive { get => _isInteractive; set { _isInteractive = value; focusable = value; EnableInClassList("utk-image-toggle-btn--non-interactive", !value); } } #endregion #region Constructor public UTKImageToggleButton() { UTKThemeManager.Instance.ApplyThemeToElement(this); var uss = Resources.Load(USS_PATH); if (uss != null) { styleSheets.Add(uss); } CreateUI(); SetupEvents(); SubscribeToThemeChanges(); } /// /// OnIcon/OffIcon을 지정하여 생성합니다. /// Material Icon 이름 또는 Image Icon 경로를 사용할 수 있습니다. /// /// On 상태 아이콘 /// Off 상태 아이콘 /// 아이콘 크기 (픽셀) public UTKImageToggleButton(string onIcon, string offIcon, int iconSize = DEFAULT_ICON_SIZE) : this() { _onIcon = onIcon; _offIcon = offIcon; _iconSize = iconSize; UpdateIconDisplay(); } #endregion #region Setup private void CreateUI() { AddToClassList("utk-image-toggle-btn"); focusable = true; pickingMode = PickingMode.Position; var asset = Resources.Load(UXML_PATH); if (asset != null) { var root = asset.Instantiate(); _materialIconLabel = root.Q