UTKToolBar 개발 완료
This commit is contained in:
382
Assets/Scripts/UVC/UIToolkit/ToolBar/UTKToolBarModel.cs
Normal file
382
Assets/Scripts/UVC/UIToolkit/ToolBar/UTKToolBarModel.cs
Normal file
@@ -0,0 +1,382 @@
|
||||
#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;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>전체 아이템 목록 (순서 유지)</summary>
|
||||
public List<IUTKToolBarItem> Items { get; private set; } = new();
|
||||
|
||||
#endregion
|
||||
|
||||
#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
|
||||
};
|
||||
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
|
||||
};
|
||||
// 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
|
||||
};
|
||||
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
|
||||
};
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user