#nullable enable using System; using System.Collections.Generic; using UVC.UI.Commands; namespace UVC.UIToolkit { /// /// UTKToolBar의 데이터 모델입니다. /// 아이템 컬렉션을 관리하고, 라디오 그룹 등록을 자동화합니다. /// 기존 ToolbarModel과 동일한 팩토리 API를 제공합니다. /// public class UTKToolBarModel : IDisposable { #region Fields private readonly Dictionary _radioGroups = new(); private bool _disposed; #endregion #region Properties /// 전체 아이템 목록 (순서 유지) public List Items { get; private set; } = new(); #endregion #region Add Methods /// /// 아이템을 모델에 추가합니다. /// ToolbarRadioButton이면 자동으로 그룹에 등록합니다. /// /// 추가할 아이템 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; } } /// /// 일반 버튼을 추가합니다. /// /// 버튼 텍스트 (다국어 키) /// 아이콘 경로 /// 실행할 명령 /// 툴팁 (다국어 키) /// Material Icon 사용 여부 (기본값: true) /// 생성된 버튼 데이터 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; } /// /// 토글 버튼을 추가합니다. /// /// 버튼 텍스트 /// 초기 On/Off 상태 /// On 상태 아이콘 /// Off 상태 아이콘 /// 토글 콜백 /// 실행할 명령 /// 툴팁 /// Material Icon 사용 여부 /// 생성된 토글 버튼 데이터 public UTKToolBarToggleButtonData AddToggleButton( string text, bool initialState = false, string? onIconPath = null, string? offIconPath = null, Action? 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; } /// /// 라디오 버튼을 추가합니다. /// /// 라디오 그룹 이름 /// 버튼 텍스트 /// 초기 선택 상태 /// 선택 상태 아이콘 /// 비선택 상태 아이콘 /// 토글 콜백 /// 실행할 명령 /// 툴팁 /// Material Icon 사용 여부 /// 생성된 라디오 버튼 데이터 public UTKToolBarRadioButtonData AddRadioButton( string groupName, string text, bool initialState = false, string? onIconPath = null, string? offIconPath = null, Action? 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; } /// /// 확장 버튼을 추가합니다. /// /// 버튼 텍스트 /// 아이콘 경로 /// 실행할 명령 /// 툴팁 /// 서브 선택 시 아이콘 업데이트 여부 /// Material Icon 사용 여부 /// 생성된 확장 버튼 데이터 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; } /// /// 구분선을 추가합니다. /// /// 생성된 구분선 데이터 public UTKToolBarSeparatorData AddSeparator() { var separator = new UTKToolBarSeparatorData(); AddItem(separator); return separator; } #endregion #region State Management /// /// 라디오 그룹의 특정 버튼을 선택합니다. /// /// 그룹 이름 /// 선택할 버튼. null이면 모두 해제. /// 이벤트 발생 여부 /// 성공 여부 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; } /// /// 텍스트로 라디오 버튼을 찾아 선택합니다. /// /// 그룹 이름 /// 버튼 텍스트. null이면 모두 해제. /// 이벤트 발생 여부 /// 선택된 버튼 또는 null 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; } /// /// 라디오 그룹 선택 해제. /// /// 그룹 이름 /// 이벤트 발생 여부 /// 성공 여부 public bool ClearRadioButtonSelection(string groupName, bool raiseEvent = true) { return SetRadioButtonSelection(groupName, null, raiseEvent); } /// /// 토글 버튼 상태 변경. /// /// 토글 버튼 /// 설정할 상태 /// 이벤트 발생 여부 public void SetToggleButtonState(UTKToolBarToggleButtonData toggleButton, bool isSelected, bool raiseEvent = true) { toggleButton.SetSelected(isSelected, raiseEvent); } /// /// 텍스트로 토글 버튼을 찾아 상태를 변경합니다. /// /// 버튼 텍스트 /// 설정할 상태 /// 이벤트 발생 여부 /// 찾은 토글 버튼 또는 null 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; } /// /// 텍스트로 토글 버튼 상태를 조회합니다. /// /// 버튼 텍스트 /// 선택 상태. 버튼을 찾지 못하면 false. 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; } /// /// 라디오 그룹을 가져옵니다. /// /// 그룹 이름 /// 라디오 그룹 또는 null public UTKToolBarRadioButtonGroup? GetRadioButtonGroup(string groupName) { return _radioGroups.TryGetValue(groupName, out var group) ? group : null; } #endregion #region IDisposable /// /// 모든 아이템과 라디오 그룹을 정리합니다. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 리소스 정리 구현. /// /// 관리 리소스 정리 여부 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 } }