Files
XRLib/Assets/Scripts/UVC/UIToolkit/Property/Items/Base/UTKPropertyItemBase.cs
2026-02-04 20:31:52 +09:00

195 lines
5.9 KiB
C#

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