UTKToolBar 개발 완료
This commit is contained in:
13
Assets/Scripts/UVC/UIToolkit/ToolBar/Data/IUTKToolBarItem.cs
Normal file
13
Assets/Scripts/UVC/UIToolkit/ToolBar/Data/IUTKToolBarItem.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
#nullable enable
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 툴바에 추가될 수 있는 모든 항목(버튼, 구분선 등)의 기본 인터페이스입니다.
|
||||
/// </summary>
|
||||
public interface IUTKToolBarItem
|
||||
{
|
||||
/// <summary>아이템 고유 식별자</summary>
|
||||
string ItemId { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aba55b5f2a940314f9c7057358cbbaab
|
||||
@@ -0,0 +1,198 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using UVC.UI.Commands;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 모든 툴바 버튼의 공통 데이터를 정의하는 추상 클래스입니다.
|
||||
/// Text, Icon, Enabled, Tooltip, Command 등의 공통 속성과 상태 변경 이벤트를 제공합니다.
|
||||
/// </summary>
|
||||
public abstract class UTKToolBarButtonData : IUTKToolBarItem, IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string _text = "";
|
||||
private string? _iconPath;
|
||||
private bool _isEnabled = true;
|
||||
private bool _disposed;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>아이템 고유 식별자</summary>
|
||||
public string ItemId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 버튼 텍스트 (다국어 키). 변경 시 OnStateChanged 이벤트 발생.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get => _text;
|
||||
set
|
||||
{
|
||||
if (_text != value)
|
||||
{
|
||||
_text = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 아이콘 경로. Material Icon 유니코드 또는 Resources 경로.
|
||||
/// 변경 시 OnStateChanged 이벤트 발생.
|
||||
/// </summary>
|
||||
public string? IconPath
|
||||
{
|
||||
get => _iconPath;
|
||||
set
|
||||
{
|
||||
if (_iconPath != value)
|
||||
{
|
||||
_iconPath = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Material Icon 사용 여부 (true: 폰트 아이콘, false: 이미지)</summary>
|
||||
public bool UseMaterialIcon { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 활성화 상태. 변경 시 OnStateChanged 이벤트 발생.
|
||||
/// </summary>
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (_isEnabled != value)
|
||||
{
|
||||
_isEnabled = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>툴팁 텍스트 (다국어 키)</summary>
|
||||
public string? Tooltip { get; set; }
|
||||
|
||||
/// <summary>실행할 명령</summary>
|
||||
public ICommand? ClickCommand { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>Text, Icon, Enabled 등 시각적 상태 변경 시 발생</summary>
|
||||
public event Action? OnStateChanged;
|
||||
|
||||
/// <summary>버튼 클릭 시 발생</summary>
|
||||
public event Action? OnClicked;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarButtonData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
protected UTKToolBarButtonData(string? itemId = null)
|
||||
{
|
||||
ItemId = itemId ?? Guid.NewGuid().ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 클릭 실행. Command 실행 + OnClicked 이벤트 발생.
|
||||
/// IUndoableCommand인 경우 UndoRedoManager를 통해 실행합니다.
|
||||
/// </summary>
|
||||
/// <param name="parameter">ClickCommand에 전달할 파라미터</param>
|
||||
public virtual void ExecuteClick(object? parameter = null)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
if (ClickCommand != null)
|
||||
{
|
||||
if (ClickCommand is IUndoableCommand undoableCommand)
|
||||
{
|
||||
var undoRedoManager = UnityEngine.Object.FindAnyObjectByType<UVC.Studio.Manager.UndoRedoManager>();
|
||||
if (undoRedoManager != null)
|
||||
{
|
||||
undoRedoManager.ExecuteCommand(undoableCommand, parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClickCommand.Execute(parameter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ClickCommand.Execute(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
OnClicked?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnStateChanged 이벤트를 수동으로 발생시킵니다.
|
||||
/// 여러 속성을 변경 후 한 번에 UI 업데이트를 트리거할 때 사용합니다.
|
||||
/// </summary>
|
||||
public void NotifyStateChanged()
|
||||
{
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 이벤트 핸들러를 해제합니다.
|
||||
/// </summary>
|
||||
public virtual void ClearEventHandlers()
|
||||
{
|
||||
OnStateChanged = null;
|
||||
OnClicked = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// 리소스를 정리합니다. Command가 IDisposable이면 함께 정리합니다.
|
||||
/// </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)
|
||||
{
|
||||
ClearEventHandlers();
|
||||
if (ClickCommand is IDisposable disposableCommand)
|
||||
{
|
||||
disposableCommand.Dispose();
|
||||
}
|
||||
ClickCommand = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cacd491a50884cc44a93efc10241adc0
|
||||
@@ -0,0 +1,144 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 서브 버튼 목록을 가진 확장 가능한 버튼 데이터입니다.
|
||||
/// 클릭 시 서브 메뉴를 표시하고, 서브 버튼 선택 시 메인 아이콘을 업데이트할 수 있습니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarExpandableButtonData : UTKToolBarButtonData
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private UTKToolBarButtonData? _selectedSubButton;
|
||||
private string _originalText = "";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>서브 버튼 목록</summary>
|
||||
public List<UTKToolBarButtonData> SubButtons { get; private set; } = new();
|
||||
|
||||
/// <summary>서브 버튼 선택 시 메인 아이콘 업데이트 여부</summary>
|
||||
public bool UpdateIconOnSelection { get; set; }
|
||||
|
||||
/// <summary>현재 선택된 서브 버튼</summary>
|
||||
public UTKToolBarButtonData? SelectedSubButton => _selectedSubButton;
|
||||
|
||||
/// <summary>원본 텍스트 (서브 버튼 선택 시 변경 전 저장용)</summary>
|
||||
public string OriginalText => _originalText;
|
||||
|
||||
/// <summary>서브 버튼 선택 콜백</summary>
|
||||
public Action<UTKToolBarButtonData>? OnSubButtonSelected { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>서브 버튼 선택 변경 이벤트 (mainText, selectedSubText)</summary>
|
||||
public event Action<string, string>? OnSubButtonSelectionChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarExpandableButtonData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
public UTKToolBarExpandableButtonData(string? itemId = null) : base(itemId)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 원본 텍스트를 설정합니다. AddExpandableButton에서 호출됩니다.
|
||||
/// </summary>
|
||||
/// <param name="text">원본 텍스트</param>
|
||||
public void SetOriginalText(string text)
|
||||
{
|
||||
_originalText = text;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 서브 버튼을 선택합니다. UpdateIconOnSelection이 true이면 메인 아이콘도 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="selectedSubButton">선택할 서브 버튼</param>
|
||||
public void SelectSubButton(UTKToolBarButtonData selectedSubButton)
|
||||
{
|
||||
if (selectedSubButton == null || !selectedSubButton.IsEnabled) return;
|
||||
|
||||
// 동일 버튼 재선택 시 무시
|
||||
if (_selectedSubButton == selectedSubButton) return;
|
||||
|
||||
_selectedSubButton = selectedSubButton;
|
||||
|
||||
if (UpdateIconOnSelection)
|
||||
{
|
||||
if (Text != selectedSubButton.Text)
|
||||
{
|
||||
Text = selectedSubButton.Text;
|
||||
}
|
||||
if (IconPath != selectedSubButton.IconPath)
|
||||
{
|
||||
IconPath = selectedSubButton.IconPath;
|
||||
}
|
||||
}
|
||||
|
||||
OnSubButtonSelected?.Invoke(selectedSubButton);
|
||||
OnSubButtonSelectionChanged?.Invoke(_originalText, selectedSubButton.Text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 클릭 실행. 기본 Command를 실행합니다.
|
||||
/// 서브 메뉴 표시/숨김은 View에서 처리합니다.
|
||||
/// </summary>
|
||||
/// <param name="parameter">ClickCommand에 전달할 파라미터</param>
|
||||
public override void ExecuteClick(object? parameter = null)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
base.ExecuteClick(parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 이벤트 핸들러를 해제합니다. 서브 버튼의 핸들러도 정리합니다.
|
||||
/// </summary>
|
||||
public override void ClearEventHandlers()
|
||||
{
|
||||
base.ClearEventHandlers();
|
||||
OnSubButtonSelected = null;
|
||||
OnSubButtonSelectionChanged = null;
|
||||
|
||||
foreach (var subButton in SubButtons)
|
||||
{
|
||||
subButton.ClearEventHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 리소스 정리. 서브 버튼도 재귀적으로 정리합니다.
|
||||
/// </summary>
|
||||
/// <param name="disposing">관리 리소스 정리 여부</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
foreach (var subButton in SubButtons)
|
||||
{
|
||||
subButton.Dispose();
|
||||
}
|
||||
SubButtons.Clear();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aa64cd1b0827c724b965c2fba2d37ce1
|
||||
@@ -0,0 +1,79 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 그룹 내 상호 배타적 선택을 지원하는 라디오 버튼 데이터입니다.
|
||||
/// 동일한 GroupName을 가진 라디오 버튼들 중 하나만 선택됩니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarRadioButtonData : UTKToolBarToggleButtonData
|
||||
{
|
||||
#region Properties
|
||||
|
||||
/// <summary>소속 라디오 그룹 이름</summary>
|
||||
public string GroupName { get; private set; }
|
||||
|
||||
/// <summary>라디오 그룹 참조 (모델에서 설정)</summary>
|
||||
internal UTKToolBarRadioButtonGroup? RadioGroup { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarRadioButtonData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="groupName">소속 라디오 그룹 이름. null이거나 비어있을 수 없습니다.</param>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
/// <exception cref="ArgumentNullException">groupName이 null이거나 빈 문자열일 경우</exception>
|
||||
public UTKToolBarRadioButtonData(string groupName, string? itemId = null) : base(itemId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(groupName))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(groupName), "라디오 버튼은 반드시 GroupName을 가져야 합니다.");
|
||||
}
|
||||
GroupName = groupName;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 클릭 시 그룹 내 다른 버튼은 해제하고 이 버튼만 선택합니다.
|
||||
/// 선택된 상태에서만 ClickCommand가 실행됩니다.
|
||||
/// </summary>
|
||||
/// <param name="parameter">ClickCommand에 전달할 파라미터</param>
|
||||
public override void ExecuteClick(object? parameter = null)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
if (RadioGroup != null)
|
||||
{
|
||||
RadioGroup.SetSelected(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"UTKToolBarRadioButtonData '{Text}' (그룹: {GroupName})에 RadioGroup이 할당되지 않았습니다.");
|
||||
}
|
||||
|
||||
// 선택된 상태에서만 Command 실행
|
||||
if (IsSelected && ClickCommand != null)
|
||||
{
|
||||
ClickCommand.Execute(parameter ?? this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 이벤트 핸들러를 해제합니다.
|
||||
/// </summary>
|
||||
public override void ClearEventHandlers()
|
||||
{
|
||||
base.ClearEventHandlers();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18507fdc9b7c65649b9f5604b45532d8
|
||||
@@ -0,0 +1,165 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 라디오 버튼 그룹을 관리합니다. 하나의 버튼만 선택 상태를 유지합니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarRadioButtonGroup : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly List<UTKToolBarRadioButtonData> _buttons = new();
|
||||
private bool _disposed;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>그룹 이름</summary>
|
||||
public string GroupName { get; private set; }
|
||||
|
||||
/// <summary>현재 선택된 버튼</summary>
|
||||
public UTKToolBarRadioButtonData? SelectedButton { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarRadioButtonGroup의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="groupName">그룹 이름</param>
|
||||
public UTKToolBarRadioButtonGroup(string groupName)
|
||||
{
|
||||
GroupName = groupName;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 버튼을 그룹에 등록합니다.
|
||||
/// </summary>
|
||||
/// <param name="button">등록할 라디오 버튼</param>
|
||||
public void RegisterButton(UTKToolBarRadioButtonData button)
|
||||
{
|
||||
if (!_buttons.Contains(button))
|
||||
{
|
||||
_buttons.Add(button);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 버튼을 선택합니다. 나머지 버튼은 해제됩니다.
|
||||
/// </summary>
|
||||
/// <param name="buttonToSelect">선택할 버튼</param>
|
||||
/// <param name="raiseEvent">이벤트 발생 여부</param>
|
||||
public void SetSelected(UTKToolBarRadioButtonData? buttonToSelect, bool raiseEvent = true)
|
||||
{
|
||||
if (buttonToSelect != null && !_buttons.Contains(buttonToSelect))
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"SetSelected: 버튼 '{buttonToSelect.Text}'은 그룹 '{GroupName}'에 등록되어 있지 않습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 이미 선택된 버튼을 다시 클릭한 경우 무시
|
||||
if (SelectedButton == buttonToSelect && buttonToSelect != null && buttonToSelect.IsSelected)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SelectedButton = buttonToSelect;
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
bool shouldBeSelected = (button == buttonToSelect);
|
||||
button.SetSelected(shouldBeSelected, raiseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 선택을 해제합니다.
|
||||
/// </summary>
|
||||
/// <param name="raiseEvent">이벤트 발생 여부</param>
|
||||
public void ClearSelection(bool raiseEvent = true)
|
||||
{
|
||||
SelectedButton = null;
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
button.SetSelected(false, raiseEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 그룹 내 버튼 목록을 반환합니다.
|
||||
/// </summary>
|
||||
/// <returns>버튼 목록 (읽기 전용)</returns>
|
||||
public IReadOnlyList<UTKToolBarRadioButtonData> GetButtons()
|
||||
{
|
||||
return _buttons.AsReadOnly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 텍스트로 버튼을 검색합니다.
|
||||
/// </summary>
|
||||
/// <param name="text">검색할 텍스트</param>
|
||||
/// <returns>일치하는 버튼 또는 null</returns>
|
||||
public UTKToolBarRadioButtonData? FindButtonByText(string text)
|
||||
{
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
if (string.Equals(button.Text, text, StringComparison.Ordinal))
|
||||
{
|
||||
return button;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 초기 선택 상태를 적용합니다.
|
||||
/// IsSelected가 true인 버튼이 있으면 해당 버튼을 선택합니다.
|
||||
/// </summary>
|
||||
internal void InitializeSelection()
|
||||
{
|
||||
if (_buttons.Count == 0) return;
|
||||
|
||||
UTKToolBarRadioButtonData? initialButton = null;
|
||||
foreach (var button in _buttons)
|
||||
{
|
||||
if (button.IsSelected)
|
||||
{
|
||||
initialButton = button;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (initialButton != null)
|
||||
{
|
||||
SetSelected(initialButton);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <summary>
|
||||
/// 리소스를 정리합니다.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed) return;
|
||||
_disposed = true;
|
||||
|
||||
_buttons.Clear();
|
||||
SelectedButton = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d601a9d6935c50a40b474d4587c15deb
|
||||
@@ -0,0 +1,24 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 툴바 내 시각적 구분선 데이터입니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarSeparatorData : IUTKToolBarItem
|
||||
{
|
||||
/// <summary>아이템 고유 식별자</summary>
|
||||
public string ItemId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarSeparatorData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
public UTKToolBarSeparatorData(string? itemId = null)
|
||||
{
|
||||
ItemId = itemId ?? Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96caf0e0ca9659b4eb7f8c1b56139813
|
||||
@@ -0,0 +1,18 @@
|
||||
#nullable enable
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// 단순 클릭 동작의 일반 버튼 데이터입니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarStandardButtonData : UTKToolBarButtonData
|
||||
{
|
||||
/// <summary>
|
||||
/// UTKToolBarStandardButtonData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
public UTKToolBarStandardButtonData(string? itemId = null) : base(itemId)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: baa2093a77f0b6c42bda1eab25c03ce2
|
||||
@@ -0,0 +1,135 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
|
||||
namespace UVC.UIToolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// On/Off 상태를 가지는 토글 버튼 데이터입니다.
|
||||
/// 클릭 시 IsSelected 상태가 반전되고, OnToggleStateChanged 이벤트가 발생합니다.
|
||||
/// </summary>
|
||||
public class UTKToolBarToggleButtonData : UTKToolBarButtonData
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private bool _isSelected;
|
||||
private string? _offIconPath;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택(On) 상태. 변경 시 OnToggleStateChanged, OnStateChanged 이벤트 발생.
|
||||
/// </summary>
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
OnToggle?.Invoke(_isSelected);
|
||||
OnToggleStateChanged?.Invoke(_isSelected);
|
||||
NotifyStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Off 상태 아이콘 경로</summary>
|
||||
public string? OffIconPath
|
||||
{
|
||||
get => _offIconPath;
|
||||
set
|
||||
{
|
||||
if (_offIconPath != value)
|
||||
{
|
||||
_offIconPath = value;
|
||||
NotifyStateChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>토글 상태 변경 시 콜백</summary>
|
||||
public Action<bool>? OnToggle { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>IsSelected 상태 변경 시 발생</summary>
|
||||
public event Action<bool>? OnToggleStateChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
/// <summary>
|
||||
/// UTKToolBarToggleButtonData의 새 인스턴스를 초기화합니다.
|
||||
/// </summary>
|
||||
/// <param name="itemId">아이템 고유 식별자. null이면 GUID 자동 생성.</param>
|
||||
public UTKToolBarToggleButtonData(string? itemId = null) : base(itemId)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// 이벤트 발생 여부를 선택하여 선택 상태를 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="isSelected">새로운 선택 상태</param>
|
||||
/// <param name="raiseEvent">true이면 OnToggle 콜백을 호출, false이면 UI 이벤트만 발생</param>
|
||||
public void SetSelected(bool isSelected, bool raiseEvent = true)
|
||||
{
|
||||
if (_isSelected != isSelected)
|
||||
{
|
||||
_isSelected = isSelected;
|
||||
if (raiseEvent)
|
||||
{
|
||||
OnToggle?.Invoke(_isSelected);
|
||||
}
|
||||
OnToggleStateChanged?.Invoke(_isSelected);
|
||||
NotifyStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 클릭 시 상태를 반전시키고 Command를 실행합니다.
|
||||
/// </summary>
|
||||
/// <param name="parameter">전달된 파라미터. bool이면 직접 상태 설정, 아니면 토글.</param>
|
||||
public override void ExecuteClick(object? parameter = null)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
if (parameter is bool newState)
|
||||
{
|
||||
IsSelected = newState;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsSelected = !IsSelected;
|
||||
}
|
||||
|
||||
// Command 실행 (현재 IsSelected 상태를 파라미터로 전달)
|
||||
if (ClickCommand != null)
|
||||
{
|
||||
ClickCommand.Execute(IsSelected);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 모든 이벤트 핸들러를 해제합니다.
|
||||
/// </summary>
|
||||
public override void ClearEventHandlers()
|
||||
{
|
||||
base.ClearEventHandlers();
|
||||
OnToggleStateChanged = null;
|
||||
OnToggle = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 368ce741cc208274989e0f6e37be2d87
|
||||
Reference in New Issue
Block a user