#nullable enable using System; using UnityEngine; namespace UVC.UIToolkit { /// /// 모든 PropertyItem의 기본 추상 클래스입니다. /// 순수 데이터 클래스로, UI는 별도의 View 클래스에서 담당합니다. /// /// 주요 기능: /// /// 속성 값 관리 (Value, IsReadOnly, IsVisible) /// 값 변경 이벤트 발생 /// 메타데이터 관리 (Description, Tooltip, GroupId) /// /// /// View-Data 분리: /// /// Data (UTKPropertyItemBase): 이 클래스 - 속성 값과 메타데이터 /// View (UTKPropertyItemViewBase): UI 표시 및 사용자 상호작용 /// Factory (UTKPropertyItemViewFactory): Data에 맞는 View 생성 /// /// /// 속성 값의 타입 public abstract class UTKPropertyItemBase : IUTKPropertyItem, IDisposable { #region Fields protected T _value; protected bool _isReadOnly; protected bool _isVisible = true; protected bool _showLabel = true; private string? _description; protected string? _tooltip; private string? _groupId; private bool _disposed; #endregion #region Properties /// 고유 ID public string Id { get; } /// 표시 이름 public string Name { get; } /// 표시 이름 (Name과 동일) public string DisplayName => Name; /// 그룹 여부 (항상 false) public bool IsGroup => false; /// TreeView 내부 ID public int TreeViewId { get; set; } /// 속성 타입 public abstract UTKPropertyType PropertyType { get; } /// 현재 값 public T Value { get => _value; set { if (!Equals(_value, value)) { var oldValue = _value; _value = value; NotifyValueChanged(oldValue, value, true); } } } /// 설명 (부가 정보) public string? Description { get => _description; set => _description = value; } /// 툴팁 텍스트 public string? Tooltip { get => _tooltip; set => _tooltip = value; } /// 읽기 전용 여부 public bool IsReadOnly { get => _isReadOnly; set { if (_isReadOnly == value) return; _isReadOnly = value; OnStateChanged?.Invoke(this); } } /// 표시 여부 public bool IsVisible { get => _isVisible; set => _isVisible = value; } /// 소속 그룹 ID public string? GroupId { get => _groupId; set => _groupId = value; } /// 라벨 표시 여부 (false면 value가 전체 너비 사용) public bool ShowLabel { get => _showLabel; set{ if (_showLabel == value) return; _showLabel = value; OnStateChanged?.Invoke(this); } } #endregion #region Events /// 값 변경 이벤트 (object 타입) public event Action? OnValueChanged; /// 값 변경 이벤트 (제네릭 타입) public event Action, T, T>? OnTypedValueChanged; /// 상태(ReadOnly 등) 변경 이벤트 public event Action? OnStateChanged; #endregion #region Constructor /// /// PropertyItem을 생성합니다. /// /// 고유 ID /// 표시 이름 /// 초기 값 protected UTKPropertyItemBase(string id, string name, T initialValue) { Id = id ?? throw new ArgumentNullException(nameof(id)); Name = name ?? throw new ArgumentNullException(nameof(name)); _value = initialValue; } #endregion #region Public Methods /// 현재 값을 object로 반환합니다. public object? GetValue() => _value; /// 값을 설정합니다 (타입 변환 포함). public void SetValue(object? value, bool notifyChangeEvent = false) { if (value == null) { if (default(T) == null) { if (!Equals(_value, value)) { var oldValue = _value; _value = default!; NotifyValueChanged(oldValue, default!, notifyChangeEvent); } } } else if (value is T typedValue) { if (!Equals(_value, typedValue)) { var oldValue = _value; _value = typedValue; NotifyValueChanged(oldValue, typedValue, notifyChangeEvent); } } else { try { var v = (T)Convert.ChangeType(value, typeof(T)); if (!Equals(_value, v)) { var oldValue = _value; _value = v; NotifyValueChanged(oldValue, v, notifyChangeEvent); } } catch (Exception ex) { Debug.LogWarning($"[UTKPropertyItem] Failed to convert value '{value}' to type {typeof(T)}: {ex.Message}"); } } } #endregion #region Protected Methods /// 값 변경을 알립니다. protected void NotifyValueChanged(T oldValue, T newValue, bool notifyChangeEvent = false) { OnTypedValueChanged?.Invoke(this, oldValue, newValue); OnValueChanged?.Invoke(this, oldValue, newValue, notifyChangeEvent); } #endregion #region IDisposable /// 리소스를 해제합니다. public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// 리소스를 해제합니다. protected virtual void Dispose(bool disposing) { if (_disposed) return; _disposed = true; if (disposing) { OnValueChanged = null; OnTypedValueChanged = null; OnStateChanged = null; } } #endregion } }