Files
EnglewoodLAB/Assets/Scripts/UVC/UIToolkit/ToolBar/UTKToolBarModel.cs

394 lines
14 KiB
C#

#nullable enable
using System;
using System.Collections.Generic;
using UVC.UI.Commands;
namespace UVC.UIToolkit
{
/// <summary>
/// UTKToolBar의 데이터 모델입니다.
/// 아이템 컬렉션을 관리하고, 라디오 그룹 등록을 자동화합니다.
/// 기존 ToolbarModel과 동일한 팩토리 API를 제공합니다.
/// </summary>
public class UTKToolBarModel : IDisposable
{
#region Fields
private readonly Dictionary<string, UTKToolBarRadioButtonGroup> _radioGroups = new();
private bool _disposed;
private bool _showTextLabels = false;
#endregion
#region Properties
/// <summary>전체 아이템 목록 (순서 유지)</summary>
public List<IUTKToolBarItem> Items { get; private set; } = new();
#endregion
public UTKToolBarModel(bool showTextLabels = false)
{
_showTextLabels = showTextLabels;
}
#region Add Methods
/// <summary>
/// 아이템을 모델에 추가합니다.
/// ToolbarRadioButton이면 자동으로 그룹에 등록합니다.
/// </summary>
/// <param name="item">추가할 아이템</param>
public void AddItem(IUTKToolBarItem item)
{
Items.Add(item);
if (item is UTKToolBarRadioButtonData radioButton)
{
if (!_radioGroups.TryGetValue(radioButton.GroupName, out var group))
{
group = new UTKToolBarRadioButtonGroup(radioButton.GroupName);
_radioGroups.Add(radioButton.GroupName, group);
}
group.RegisterButton(radioButton);
radioButton.RadioGroup = group;
}
}
/// <summary>
/// 일반 버튼을 추가합니다.
/// </summary>
/// <param name="text">버튼 텍스트 (다국어 키)</param>
/// <param name="iconPath">아이콘 경로</param>
/// <param name="command">실행할 명령</param>
/// <param name="tooltip">툴팁 (다국어 키)</param>
/// <param name="useMaterialIcon">Material Icon 사용 여부 (기본값: true)</param>
/// <returns>생성된 버튼 데이터</returns>
public UTKToolBarStandardButtonData AddStandardButton(
string text,
string? iconPath = null,
ICommand? command = null,
string? tooltip = null,
bool useMaterialIcon = true)
{
var button = new UTKToolBarStandardButtonData
{
Text = text,
IconPath = iconPath,
ClickCommand = command,
Tooltip = tooltip,
UseMaterialIcon = useMaterialIcon,
ShowLabel = _showTextLabels
};
AddItem(button);
return button;
}
/// <summary>
/// 토글 버튼을 추가합니다.
/// </summary>
/// <param name="text">버튼 텍스트</param>
/// <param name="initialState">초기 On/Off 상태</param>
/// <param name="onIconPath">On 상태 아이콘</param>
/// <param name="offIconPath">Off 상태 아이콘</param>
/// <param name="onToggle">토글 콜백</param>
/// <param name="command">실행할 명령</param>
/// <param name="tooltip">툴팁</param>
/// <param name="useMaterialIcon">Material Icon 사용 여부</param>
/// <returns>생성된 토글 버튼 데이터</returns>
public UTKToolBarToggleButtonData AddToggleButton(
string text,
bool initialState = false,
string? onIconPath = null,
string? offIconPath = null,
Action<bool>? onToggle = null,
ICommand? command = null,
string? tooltip = null,
bool useMaterialIcon = true)
{
var button = new UTKToolBarToggleButtonData
{
Text = text,
IconPath = onIconPath,
OffIconPath = offIconPath,
OnToggle = onToggle,
ClickCommand = command,
Tooltip = tooltip,
UseMaterialIcon = useMaterialIcon,
ShowLabel = _showTextLabels
};
// IsSelected를 직접 필드에 설정 (이벤트 발생 방지)
button.SetSelected(initialState, false);
AddItem(button);
return button;
}
/// <summary>
/// 라디오 버튼을 추가합니다.
/// </summary>
/// <param name="groupName">라디오 그룹 이름</param>
/// <param name="text">버튼 텍스트</param>
/// <param name="initialState">초기 선택 상태</param>
/// <param name="onIconPath">선택 상태 아이콘</param>
/// <param name="offIconPath">비선택 상태 아이콘</param>
/// <param name="onToggle">토글 콜백</param>
/// <param name="command">실행할 명령</param>
/// <param name="tooltip">툴팁</param>
/// <param name="useMaterialIcon">Material Icon 사용 여부</param>
/// <returns>생성된 라디오 버튼 데이터</returns>
public UTKToolBarRadioButtonData AddRadioButton(
string groupName,
string text,
bool initialState = false,
string? onIconPath = null,
string? offIconPath = null,
Action<bool>? onToggle = null,
ICommand? command = null,
string? tooltip = null,
bool useMaterialIcon = true)
{
var button = new UTKToolBarRadioButtonData(groupName)
{
Text = text,
IconPath = onIconPath,
OffIconPath = offIconPath,
OnToggle = onToggle,
ClickCommand = command,
Tooltip = tooltip,
UseMaterialIcon = useMaterialIcon,
ShowLabel = _showTextLabels
};
button.SetSelected(initialState, false);
AddItem(button);
// initialState가 true이면 그룹에서 명시적으로 선택
if (initialState && _radioGroups.TryGetValue(groupName, out var group))
{
group.SetSelected(button, false);
}
return button;
}
/// <summary>
/// 확장 버튼을 추가합니다.
/// </summary>
/// <param name="text">버튼 텍스트</param>
/// <param name="iconPath">아이콘 경로</param>
/// <param name="command">실행할 명령</param>
/// <param name="tooltip">툴팁</param>
/// <param name="updateIconOnSelection">서브 선택 시 아이콘 업데이트 여부</param>
/// <param name="useMaterialIcon">Material Icon 사용 여부</param>
/// <returns>생성된 확장 버튼 데이터</returns>
public UTKToolBarExpandableButtonData AddExpandableButton(
string text,
string? iconPath = null,
ICommand? command = null,
string? tooltip = null,
bool updateIconOnSelection = false,
bool useMaterialIcon = true)
{
var button = new UTKToolBarExpandableButtonData
{
Text = text,
IconPath = iconPath,
ClickCommand = command,
Tooltip = tooltip,
UpdateIconOnSelection = updateIconOnSelection,
UseMaterialIcon = useMaterialIcon,
ShowLabel = _showTextLabels
};
button.SetOriginalText(text);
AddItem(button);
return button;
}
/// <summary>
/// 구분선을 추가합니다.
/// </summary>
/// <returns>생성된 구분선 데이터</returns>
public UTKToolBarSeparatorData AddSeparator()
{
var separator = new UTKToolBarSeparatorData();
AddItem(separator);
return separator;
}
#endregion
#region State Management
/// <summary>
/// 라디오 그룹의 특정 버튼을 선택합니다.
/// </summary>
/// <param name="groupName">그룹 이름</param>
/// <param name="buttonToSelect">선택할 버튼. null이면 모두 해제.</param>
/// <param name="raiseEvent">이벤트 발생 여부</param>
/// <returns>성공 여부</returns>
public bool SetRadioButtonSelection(string groupName, UTKToolBarRadioButtonData? buttonToSelect, bool raiseEvent = true)
{
if (!_radioGroups.TryGetValue(groupName, out var group))
{
UnityEngine.Debug.LogWarning($"SetRadioButtonSelection: 그룹 '{groupName}'을 찾을 수 없습니다.");
return false;
}
if (buttonToSelect == null)
{
group.ClearSelection(raiseEvent);
}
else
{
group.SetSelected(buttonToSelect, raiseEvent);
}
return true;
}
/// <summary>
/// 텍스트로 라디오 버튼을 찾아 선택합니다.
/// </summary>
/// <param name="groupName">그룹 이름</param>
/// <param name="buttonText">버튼 텍스트. null이면 모두 해제.</param>
/// <param name="raiseEvent">이벤트 발생 여부</param>
/// <returns>선택된 버튼 또는 null</returns>
public UTKToolBarRadioButtonData? SetRadioButtonSelectionByText(string groupName, string? buttonText, bool raiseEvent = true)
{
if (!_radioGroups.TryGetValue(groupName, out var group))
{
UnityEngine.Debug.LogWarning($"SetRadioButtonSelectionByText: 그룹 '{groupName}'을 찾을 수 없습니다.");
return null;
}
if (string.IsNullOrEmpty(buttonText))
{
group.ClearSelection(raiseEvent);
return null;
}
var button = group.FindButtonByText(buttonText);
if (button == null)
{
UnityEngine.Debug.LogWarning($"SetRadioButtonSelectionByText: 그룹 '{groupName}'에서 '{buttonText}' 버튼을 찾을 수 없습니다.");
return null;
}
group.SetSelected(button, raiseEvent);
return button;
}
/// <summary>
/// 라디오 그룹 선택 해제.
/// </summary>
/// <param name="groupName">그룹 이름</param>
/// <param name="raiseEvent">이벤트 발생 여부</param>
/// <returns>성공 여부</returns>
public bool ClearRadioButtonSelection(string groupName, bool raiseEvent = true)
{
return SetRadioButtonSelection(groupName, null, raiseEvent);
}
/// <summary>
/// 토글 버튼 상태 변경.
/// </summary>
/// <param name="toggleButton">토글 버튼</param>
/// <param name="isSelected">설정할 상태</param>
/// <param name="raiseEvent">이벤트 발생 여부</param>
public void SetToggleButtonState(UTKToolBarToggleButtonData toggleButton, bool isSelected, bool raiseEvent = true)
{
toggleButton.SetSelected(isSelected, raiseEvent);
}
/// <summary>
/// 텍스트로 토글 버튼을 찾아 상태를 변경합니다.
/// </summary>
/// <param name="buttonText">버튼 텍스트</param>
/// <param name="isSelected">설정할 상태</param>
/// <param name="raiseEvent">이벤트 발생 여부</param>
/// <returns>찾은 토글 버튼 또는 null</returns>
public UTKToolBarToggleButtonData? SetToggleButtonStateByText(string buttonText, bool isSelected, bool raiseEvent = true)
{
foreach (var item in Items)
{
if (item is UTKToolBarToggleButtonData toggleButton && string.Equals(toggleButton.Text, buttonText, StringComparison.Ordinal))
{
toggleButton.SetSelected(isSelected, raiseEvent);
return toggleButton;
}
}
UnityEngine.Debug.LogWarning($"SetToggleButtonStateByText: '{buttonText}' 토글 버튼을 찾을 수 없습니다.");
return null;
}
/// <summary>
/// 텍스트로 토글 버튼 상태를 조회합니다.
/// </summary>
/// <param name="buttonText">버튼 텍스트</param>
/// <returns>선택 상태. 버튼을 찾지 못하면 false.</returns>
public bool GetToggleButtonState(string buttonText)
{
foreach (var item in Items)
{
if (item is UTKToolBarToggleButtonData toggleButton && string.Equals(toggleButton.Text, buttonText, StringComparison.Ordinal))
{
return toggleButton.IsSelected;
}
}
return false;
}
/// <summary>
/// 라디오 그룹을 가져옵니다.
/// </summary>
/// <param name="groupName">그룹 이름</param>
/// <returns>라디오 그룹 또는 null</returns>
public UTKToolBarRadioButtonGroup? GetRadioButtonGroup(string groupName)
{
return _radioGroups.TryGetValue(groupName, out var group) ? group : null;
}
#endregion
#region IDisposable
/// <summary>
/// 모든 아이템과 라디오 그룹을 정리합니다.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 리소스 정리 구현.
/// </summary>
/// <param name="disposing">관리 리소스 정리 여부</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
_disposed = true;
if (disposing)
{
foreach (var item in Items)
{
if (item is IDisposable disposable)
{
disposable.Dispose();
}
}
Items.Clear();
foreach (var group in _radioGroups.Values)
{
group.Dispose();
}
_radioGroups.Clear();
}
}
#endregion
}
}