320 lines
8.7 KiB
C#
320 lines
8.7 KiB
C#
#nullable enable
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
|
|
namespace UVC.UIToolkit
|
|
{
|
|
/// <summary>
|
|
/// Dropdown 속성 View 클래스입니다.
|
|
/// UTKDropdown을 사용하여 문자열 목록에서 선택합니다.
|
|
/// </summary>
|
|
[UxmlElement]
|
|
public partial class UTKDropdownPropertyItemView : UTKPropertyItemViewBase, IUTKPropertyItemView<string>
|
|
{
|
|
#region Fields
|
|
private UTKDropdown? _dropdown;
|
|
|
|
private string _value = string.Empty;
|
|
private List<string> _choices = new();
|
|
|
|
private IUTKPropertyItem<string>? _boundData;
|
|
#endregion
|
|
|
|
#region Properties
|
|
protected override string ViewTypeName => "UTKDropdownPropertyItemView";
|
|
|
|
/// <summary>현재 값</summary>
|
|
public string Value
|
|
{
|
|
get => _value;
|
|
set
|
|
{
|
|
if (_value != value)
|
|
{
|
|
_value = value ?? string.Empty;
|
|
UpdateValueUI();
|
|
OnValueChanged?.Invoke(_value);
|
|
|
|
if (_boundData != null && _boundData.Value != _value)
|
|
{
|
|
_boundData.Value = _value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>선택 가능한 항목 목록</summary>
|
|
public List<string> Choices
|
|
{
|
|
get => _choices;
|
|
set
|
|
{
|
|
_choices = value ?? new List<string>();
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.SetOptions(_choices);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Events
|
|
public event Action<string>? OnValueChanged;
|
|
#endregion
|
|
|
|
#region Constructor
|
|
public UTKDropdownPropertyItemView() : base()
|
|
{
|
|
InitializeUI();
|
|
}
|
|
|
|
public UTKDropdownPropertyItemView(UTKDropdownPropertyItem data) : base()
|
|
{
|
|
_choices = data.Choices;
|
|
_value = data.Value ?? (_choices.Count > 0 ? _choices[0] : string.Empty);
|
|
Label = data.Name;
|
|
_isReadOnly = data.IsReadOnly;
|
|
|
|
InitializeUI();
|
|
Bind(data);
|
|
}
|
|
|
|
public UTKDropdownPropertyItemView(string label, List<string> choices, string initialValue = "") : base()
|
|
{
|
|
_choices = choices ?? new List<string>();
|
|
_value = initialValue ?? (_choices.Count > 0 ? _choices[0] : string.Empty);
|
|
Label = label;
|
|
InitializeUI();
|
|
}
|
|
|
|
public UTKDropdownPropertyItemView(string label, IEnumerable<string> choices, int selectedIndex = 0) : base()
|
|
{
|
|
_choices = choices?.ToList() ?? new List<string>();
|
|
if (_choices.Count > 0 && selectedIndex >= 0 && selectedIndex < _choices.Count)
|
|
{
|
|
_value = _choices[selectedIndex];
|
|
}
|
|
Label = label;
|
|
InitializeUI();
|
|
}
|
|
#endregion
|
|
|
|
#region Initialization
|
|
private void InitializeUI()
|
|
{
|
|
AddToClassList("utk-property-item-view");
|
|
AddToClassList("utk-property-item-view--dropdown");
|
|
|
|
if (!CreateUIFromUxml())
|
|
{
|
|
CreateUIFallback();
|
|
}
|
|
|
|
// UXML에서 요소 가져오기
|
|
QueryUIElements();
|
|
|
|
// 이벤트 등록
|
|
RegisterEvents();
|
|
|
|
UpdateValueUI();
|
|
UpdateReadOnlyState();
|
|
}
|
|
|
|
private void QueryUIElements()
|
|
{
|
|
_dropdown = this.Q<UTKDropdown>("dropdown-field");
|
|
|
|
// Fallback: UXML에서 못 찾으면 생성
|
|
if (_valueContainer != null && _dropdown == null)
|
|
{
|
|
_dropdown = new UTKDropdown { name = "dropdown-field" };
|
|
_dropdown.AddToClassList("utk-property-item-view__dropdown");
|
|
_valueContainer.Add(_dropdown);
|
|
}
|
|
|
|
// 초기 값 설정
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.SetOptions(_choices);
|
|
int selectedIndex = _choices.IndexOf(_value);
|
|
_dropdown.SelectedIndex = Math.Max(0, selectedIndex);
|
|
_dropdown.IsEnabled = !IsReadOnly;
|
|
}
|
|
}
|
|
|
|
private void RegisterEvents()
|
|
{
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.OnSelectionChanged += OnDropdownChanged;
|
|
}
|
|
}
|
|
|
|
private void UnregisterEvents()
|
|
{
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.OnSelectionChanged -= OnDropdownChanged;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Override Methods
|
|
protected override void CreateValueUI(VisualElement container)
|
|
{
|
|
// UXML/QueryUIElements 기반으로 생성하므로 여기서는 생성하지 않음
|
|
}
|
|
|
|
public override void RefreshUI()
|
|
{
|
|
UpdateValueUI();
|
|
}
|
|
|
|
protected override void OnReadOnlyStateChanged(bool isReadOnly)
|
|
{
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.IsEnabled = !isReadOnly;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Event Handling
|
|
private void OnDropdownChanged(int index, string newValue)
|
|
{
|
|
if (_value != newValue)
|
|
{
|
|
_value = newValue;
|
|
OnValueChanged?.Invoke(newValue);
|
|
|
|
if (_boundData != null && _boundData.Value != newValue)
|
|
{
|
|
_boundData.Value = newValue;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Value Update
|
|
private void UpdateValueUI()
|
|
{
|
|
if (_dropdown != null && _dropdown.SelectedValue != _value)
|
|
{
|
|
_dropdown.SetSelectedValue(_value, notify: false);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Public Methods
|
|
/// <summary>선택 항목 추가</summary>
|
|
public void AddChoice(string choice)
|
|
{
|
|
if (!_choices.Contains(choice))
|
|
{
|
|
_choices.Add(choice);
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.AddOption(choice);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>선택 항목 제거</summary>
|
|
public bool RemoveChoice(string choice)
|
|
{
|
|
bool removed = _choices.Remove(choice);
|
|
if (removed && _dropdown != null)
|
|
{
|
|
_dropdown.SetOptions(_choices);
|
|
|
|
if (_value == choice && _choices.Count > 0)
|
|
{
|
|
Value = _choices[0];
|
|
}
|
|
}
|
|
return removed;
|
|
}
|
|
#endregion
|
|
|
|
#region Data Binding
|
|
public void Bind(IUTKPropertyItem data)
|
|
{
|
|
if (data is IUTKPropertyItem<string> stringData)
|
|
{
|
|
Bind(stringData);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning($"[UTKDropdownPropertyItemView] Cannot bind to non-string data: {data.GetType().Name}");
|
|
}
|
|
}
|
|
|
|
public void Bind(IUTKPropertyItem<string> data)
|
|
{
|
|
Unbind();
|
|
|
|
_boundData = data;
|
|
|
|
Label = data.Name;
|
|
_value = data.Value ?? string.Empty;
|
|
IsReadOnly = data.IsReadOnly;
|
|
IsVisible = data.IsVisible;
|
|
TooltipText = data.Tooltip;
|
|
|
|
if (data is UTKDropdownPropertyItem dropdownItem)
|
|
{
|
|
_choices = dropdownItem.Choices;
|
|
if (_dropdown != null)
|
|
{
|
|
_dropdown.SetOptions(_choices);
|
|
}
|
|
}
|
|
|
|
data.OnTypedValueChanged += OnDataValueChanged;
|
|
|
|
UpdateValueUI();
|
|
UpdateReadOnlyState();
|
|
}
|
|
|
|
public void Unbind()
|
|
{
|
|
if (_boundData != null)
|
|
{
|
|
_boundData.OnTypedValueChanged -= OnDataValueChanged;
|
|
_boundData = null;
|
|
}
|
|
}
|
|
|
|
private void OnDataValueChanged(IUTKPropertyItem<string> item, string oldValue, string newValue)
|
|
{
|
|
if (_value != newValue)
|
|
{
|
|
_value = newValue ?? string.Empty;
|
|
UpdateValueUI();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Dispose
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (_disposed) return;
|
|
|
|
if (disposing)
|
|
{
|
|
UnregisterEvents();
|
|
Unbind();
|
|
|
|
OnValueChanged = null;
|
|
_dropdown = null;
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|