#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
}
}