Modal 개발 완료. Toolbar 개발 중
This commit is contained in:
7
Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs
Normal file
7
Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 툴바에 추가될 수 있는 모든 항목(버튼, 구분선 등)의 기본 인터페이스입니다.
|
||||
/// </summary>
|
||||
public interface IToolbarItem { }
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b28bebc44774c6f4f95cb5e612baef9f
|
||||
77
Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs
Normal file
77
Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 툴바의 전체적인 컨테이너 및 관리 클래스입니다.
|
||||
/// IToolbarItem 객체들을 동적으로 추가하고 관리합니다.
|
||||
/// </summary>
|
||||
public class Toolbar
|
||||
{
|
||||
public System.Collections.Generic.List<IToolbarItem> Items { get; private set; }
|
||||
private System.Collections.Generic.Dictionary<string, ToolbarRadioButtonGroup> _radioGroups;
|
||||
|
||||
public Toolbar()
|
||||
{
|
||||
Items = new System.Collections.Generic.List<IToolbarItem>();
|
||||
_radioGroups = new System.Collections.Generic.Dictionary<string, ToolbarRadioButtonGroup>();
|
||||
}
|
||||
|
||||
public void AddItem(IToolbarItem item)
|
||||
{
|
||||
Items.Add(item);
|
||||
|
||||
if (item is ToolbarRadioButton radioButton)
|
||||
{
|
||||
if (!_radioGroups.TryGetValue(radioButton.GroupName, out var group))
|
||||
{
|
||||
group = new ToolbarRadioButtonGroup();
|
||||
_radioGroups.Add(radioButton.GroupName, group);
|
||||
}
|
||||
group.RegisterButton(radioButton);
|
||||
}
|
||||
// UI 갱신 로직 호출
|
||||
}
|
||||
|
||||
public ToolbarStandardButton AddStandardButton(string text, UnityEngine.Sprite icon = null, System.Action onClick = null, string tooltipKey = null)
|
||||
{
|
||||
var button = new ToolbarStandardButton { Text = text, Icon = icon, OnClick = onClick, TooltipKey = tooltipKey };
|
||||
AddItem(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
public ToolbarToggleButton AddToggleButton(string text, bool initialState = false, UnityEngine.Sprite icon = null, System.Action<bool> onToggle = null, string tooltipKey = null)
|
||||
{
|
||||
var button = new ToolbarToggleButton { Text = text, IsSelected = initialState, Icon = icon, OnToggle = onToggle, TooltipKey = tooltipKey };
|
||||
AddItem(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
public ToolbarRadioButton AddRadioButton(string groupName, string text, bool initialState = false, UnityEngine.Sprite icon = null, System.Action<bool> onToggle = null, string tooltipKey = null)
|
||||
{
|
||||
var button = new ToolbarRadioButton(groupName) { Text = text, IsSelected = initialState, Icon = icon, OnToggle = onToggle, TooltipKey = tooltipKey };
|
||||
// AddItem 내에서 그룹 처리가 되므로, 여기서는 IsSelected 초기값만 주의 (그룹 내 하나만 true여야 함)
|
||||
AddItem(button);
|
||||
// 그룹의 초기 선택 상태를 설정하는 로직이 추가로 필요할 수 있습니다.
|
||||
// 예를 들어, 첫 번째로 추가된 라디오 버튼을 기본 선택으로 하거나, 명시적으로 설정.
|
||||
if (initialState && _radioGroups.TryGetValue(groupName, out var group))
|
||||
{
|
||||
group.SetSelected(button);
|
||||
}
|
||||
return button;
|
||||
}
|
||||
|
||||
public ToolbarExpandableButton AddExpandableButton(string text, UnityEngine.Sprite icon = null, System.Action onClick = null, string tooltipKey = null)
|
||||
{
|
||||
var button = new ToolbarExpandableButton { Text = text, Icon = icon, OnClick = onClick, TooltipKey = tooltipKey };
|
||||
AddItem(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
public void AddSeparator()
|
||||
{
|
||||
AddItem(new ToolbarSeparator());
|
||||
}
|
||||
|
||||
// 실제 UI 렌더링 및 상호작용 로직은 이 클래스 또는 별도의 UI View 클래스에서 처리됩니다.
|
||||
// (예: Unity UI GameObject 생성, 이벤트 연결 등)
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d72ec0e29e760440b1badbdf4b051f2
|
||||
82
Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs
Normal file
82
Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 모든 버튼의 기본 추상 클래스입니다.
|
||||
/// 공통적인 속성 (예: 텍스트, 아이콘, 활성화 상태) 및 동작을 정의합니다.
|
||||
/// </summary>
|
||||
public abstract class ToolbarButtonBase : IToolbarItem
|
||||
{
|
||||
public event Action OnStateChanged; // 상태 변경 알림 이벤트
|
||||
|
||||
private string _text;
|
||||
public string Text
|
||||
{
|
||||
get => _text;
|
||||
set
|
||||
{
|
||||
if (_text != value)
|
||||
{
|
||||
_text = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite _icon;
|
||||
public Sprite Icon
|
||||
{
|
||||
get => _icon;
|
||||
set
|
||||
{
|
||||
if (_icon != value)
|
||||
{
|
||||
_icon = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isEnabled = true;
|
||||
public bool IsEnabled
|
||||
{
|
||||
get => _isEnabled;
|
||||
set
|
||||
{
|
||||
if (_isEnabled != value)
|
||||
{
|
||||
_isEnabled = value;
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _tooltipKey; // 툴팁 다국어 키
|
||||
public string TooltipKey
|
||||
{
|
||||
get => _tooltipKey;
|
||||
set
|
||||
{
|
||||
if (_tooltipKey != value)
|
||||
{
|
||||
_tooltipKey = value;
|
||||
// TooltipKey 변경 시 OnStateChanged를 호출할 필요는 일반적으로 없으나,
|
||||
// 만약 UI가 TooltipKey 자체를 표시하는 등의 로직이 있다면 필요할 수 있습니다.
|
||||
// 여기서는 툴팁 내용이 동적으로 변경되는 경우가 적다고 가정하고 생략합니다.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Action OnClick { get; set; }
|
||||
|
||||
public abstract void ExecuteClick();
|
||||
|
||||
// OnStateChanged 이벤트를 외부에서 강제로 발생시켜야 할 때 사용 (예: 복합적인 상태 변경 후)
|
||||
public void NotifyStateChanged()
|
||||
{
|
||||
OnStateChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49e156554491e3c4fb49243701695feb
|
||||
60
Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs
Normal file
60
Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 클릭 시 하위 버튼 그룹을 확장하여 보여주는 버튼입니다.
|
||||
/// 하위 버튼 선택 시, 주 버튼의 내용이 업데이트될 수 있습니다.
|
||||
/// </summary>
|
||||
public class ToolbarExpandableButton : ToolbarButtonBase
|
||||
{
|
||||
public enum ExpansionDirection { Horizontal, Vertical }
|
||||
|
||||
public List<ToolbarButtonBase> SubButtons { get; private set; }
|
||||
public ExpansionDirection Direction { get; set; } = ExpansionDirection.Vertical;
|
||||
public Action<ToolbarButtonBase> OnSubButtonSelected { get; set; }
|
||||
|
||||
public ToolbarExpandableButton()
|
||||
{
|
||||
SubButtons = new List<ToolbarButtonBase>();
|
||||
}
|
||||
|
||||
public override void ExecuteClick()
|
||||
{
|
||||
if (IsEnabled)
|
||||
{
|
||||
OnClick?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectSubButton(ToolbarButtonBase selectedSubButton)
|
||||
{
|
||||
if (selectedSubButton != null && selectedSubButton.IsEnabled)
|
||||
{
|
||||
bool changed = false;
|
||||
if (this.Text != selectedSubButton.Text)
|
||||
{
|
||||
this.Text = selectedSubButton.Text; // Setter가 OnStateChanged 호출 (단, Text가 실제로 변경되어야 함)
|
||||
changed = true;
|
||||
}
|
||||
if (this.Icon != selectedSubButton.Icon)
|
||||
{
|
||||
this.Icon = selectedSubButton.Icon; // Setter가 OnStateChanged 호출
|
||||
changed = true;
|
||||
}
|
||||
|
||||
OnSubButtonSelected?.Invoke(selectedSubButton);
|
||||
// selectedSubButton.ExecuteClick(); // 하위 버튼의 클릭 로직 실행은 선택 사항
|
||||
|
||||
if (changed) // Text나 Icon이 실제로 변경된 경우에만 명시적으로 호출하거나, 각 setter에 맡김
|
||||
{
|
||||
// NotifyStateChanged(); // Text, Icon setter가 이미 호출하므로 중복될 수 있음.
|
||||
// 만약 Text, Icon 외 다른 상태도 변경된다면 필요.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c71e02eeca4e94e4b8dedd8f9fb7e4a7
|
||||
100
Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs
Normal file
100
Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using UnityEngine;
|
||||
using UVC.Locale;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
public class ToolbarManager : MonoBehaviour
|
||||
{
|
||||
public Toolbar mainToolbar;
|
||||
public ToolbarView mainToolbarView; // Unity 에디터에서 할당
|
||||
public Transform toolbarContainer; // Unity 에디터에서 할당 (툴바 UI가 생성될 부모)
|
||||
// 여기에 HorizontalLayoutGroup 또는 VerticalLayoutGroup을 추가하는 것을 권장합니다.
|
||||
|
||||
// 버튼 프리팹들은 ToolbarView로 옮겨서 관리하는 것이 더 깔끔할 수 있습니다.
|
||||
// 현재는 ToolbarManager에서 할당하여 ToolbarView로 전달하는 방식입니다.
|
||||
public GameObject standardButtonPrefab;
|
||||
public GameObject toggleButtonPrefab;
|
||||
public GameObject radioButtonPrefab;
|
||||
public GameObject expandableButtonPrefab;
|
||||
public GameObject separatorPrefab;
|
||||
public GameObject subMenuPanelPrefab;
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
mainToolbar = new Toolbar();
|
||||
|
||||
// ToolbarView에 프리팹 설정
|
||||
if (mainToolbarView != null)
|
||||
{
|
||||
mainToolbarView.standardButtonPrefab = standardButtonPrefab;
|
||||
mainToolbarView.toggleButtonPrefab = toggleButtonPrefab;
|
||||
mainToolbarView.radioButtonPrefab = radioButtonPrefab;
|
||||
mainToolbarView.expandableButtonPrefab = expandableButtonPrefab;
|
||||
mainToolbarView.separatorPrefab = separatorPrefab;
|
||||
mainToolbarView.subMenuPanelPrefab = subMenuPanelPrefab;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("ToolbarView가 할당되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// --- 툴바 모델 구성 ---
|
||||
// "저장" 대신 다국어 키 "button_save" 사용
|
||||
mainToolbar.AddStandardButton("button_save", null, () => Debug.Log("저장 버튼 클릭됨"), "tooltip_save_button");
|
||||
|
||||
// "음소거" 대신 다국어 키 "button_mute" 사용
|
||||
mainToolbar.AddToggleButton("button_mute", false, null, (isSelected) => Debug.Log($"음소거: {isSelected}"), "tooltip_mute_button");
|
||||
|
||||
mainToolbar.AddSeparator();
|
||||
|
||||
// "펜" 대신 다국어 키 "tool_pen" 사용
|
||||
mainToolbar.AddRadioButton("ToolGroup", "tool_pen", true, null, (isSelected) => { if (isSelected) Debug.Log("펜 도구 선택됨"); }, "tooltip_pen_tool");
|
||||
// "지우개" 대신 다국어 키 "tool_eraser" 사용
|
||||
mainToolbar.AddRadioButton("ToolGroup", "tool_eraser", false, null, (isSelected) => { if (isSelected) Debug.Log("지우개 도구 선택됨"); }, "tooltip_eraser_tool");
|
||||
|
||||
mainToolbar.AddSeparator();
|
||||
|
||||
// "브러시 크기" 대신 다국어 키 "button_brush_size" 사용
|
||||
var expandableBtnModel = mainToolbar.AddExpandableButton("button_brush_size", null, null, "tooltip_brush_size");
|
||||
// 하위 버튼도 다국어 키 사용
|
||||
var smallBrush = new ToolbarStandardButton { Text = "brush_size_small", TooltipKey = "tooltip_brush_small" };
|
||||
expandableBtnModel.SubButtons.Add(smallBrush);
|
||||
expandableBtnModel.SubButtons.Add(new ToolbarStandardButton { Text = "brush_size_medium", TooltipKey = "tooltip_brush_medium" });
|
||||
expandableBtnModel.OnSubButtonSelected = (selectedSubButton) => {
|
||||
// selectedSubButton.Text 에는 이제 다국어 키가 들어있습니다.
|
||||
// 실제 표시된 텍스트를 로그로 남기려면 LocalizationManager를 사용해야 합니다.
|
||||
string localizedSubButtonText = LocalizationManager.Instance != null ? LocalizationManager.Instance.GetString(selectedSubButton.Text) : selectedSubButton.Text;
|
||||
Debug.Log($"브러시 크기 '{localizedSubButtonText}' 선택됨 (주 버튼 업데이트)");
|
||||
};
|
||||
// --- 툴바 모델 구성 끝 ---
|
||||
|
||||
|
||||
// ToolbarView 초기화 및 렌더링
|
||||
if (toolbarContainer != null)
|
||||
{
|
||||
mainToolbarView.Initialize(mainToolbar, toolbarContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("ToolbarContainer가 할당되지 않았습니다.");
|
||||
}
|
||||
|
||||
// 예시: 모델 상태를 코드로 변경하고 UI가 업데이트되는지 테스트
|
||||
// StartCoroutine(TestModelChange(saveBtnModel, muteToggleModel));
|
||||
}
|
||||
|
||||
// System.Collections.IEnumerator TestModelChange(ToolbarStandardButton standard, ToolbarToggleButton toggle)
|
||||
// {
|
||||
// yield return new WaitForSeconds(2f);
|
||||
// Debug.Log("모델 변경 테스트: 저장 버튼 비활성화 및 텍스트 변경");
|
||||
// standard.Text = "저장됨";
|
||||
// standard.IsEnabled = false;
|
||||
//
|
||||
// yield return new WaitForSeconds(2f);
|
||||
// Debug.Log("모델 변경 테스트: 음소거 토글 상태 변경");
|
||||
// toggle.IsSelected = true;
|
||||
// }
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c8047638e9a7ca4495254682609d580
|
||||
32
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs
Normal file
32
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 라디오 버튼 그룹 내에서 사용되는 버튼입니다.
|
||||
/// 그룹 내 하나의 버튼만 선택될 수 있습니다.
|
||||
/// </summary>
|
||||
public class ToolbarRadioButton : ToolbarToggleButton
|
||||
{
|
||||
public string GroupName { get; private set; }
|
||||
internal ToolbarRadioButtonGroup RadioGroup { get; set; }
|
||||
|
||||
public ToolbarRadioButton(string groupName)
|
||||
{
|
||||
GroupName = groupName;
|
||||
}
|
||||
|
||||
public override void ExecuteClick()
|
||||
{
|
||||
if (IsEnabled)
|
||||
{
|
||||
// 라디오 버튼은 직접 IsSelected를 토글하지 않고, 그룹에 의해 상태가 결정됩니다.
|
||||
// 그룹이 SetSelected를 호출하면, 해당 버튼의 IsSelected가 true로 설정되고,
|
||||
// 다른 버튼들은 false로 설정되면서 각자의 OnStateChanged 이벤트가 발생합니다.
|
||||
RadioGroup?.SetSelected(this);
|
||||
// OnClick은 그룹에 의해 선택이 확정되었을 때 호출되도록 RadioGroup.SetSelected 내부에서 처리하거나,
|
||||
// 여기서 IsSelected 상태를 확인 후 호출할 수 있습니다.
|
||||
// 현재 구조에서는 RadioGroup.SetSelected가 IsSelected를 변경하고, IsSelected의 setter가 OnStateChanged를 호출합니다.
|
||||
// OnClick은 ToolbarToggleButton의 ExecuteClick에서 이미 호출될 수 있으므로 중복 호출을 피하거나 의도에 맞게 조정합니다.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 451c776768fed71479e8c7a4a73818ea
|
||||
43
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs
Normal file
43
Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 라디오 버튼들을 그룹으로 관리하여 하나만 선택되도록 합니다.
|
||||
/// ToolbarRadioButtonGroup, ToolbarExpandableButton 클래스는 이전 제안과 거의 동일하게 유지하되,
|
||||
/// 상태 변경 시 NotifyStateChanged() 호출을 고려할 수 있습니다.
|
||||
/// 예를 들어 ToolbarExpandableButton에서 SelectSubButton 후 주 버튼의 Text, Icon이 변경되면 NotifyStateChanged() 호출
|
||||
/// </summary>
|
||||
public class ToolbarRadioButtonGroup
|
||||
{
|
||||
private List<ToolbarRadioButton> _buttons = new List<ToolbarRadioButton>();
|
||||
public ToolbarRadioButton SelectedButton { get; private set; }
|
||||
|
||||
public void RegisterButton(ToolbarRadioButton button)
|
||||
{
|
||||
if (!_buttons.Contains(button))
|
||||
{
|
||||
_buttons.Add(button);
|
||||
button.RadioGroup = this;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSelected(ToolbarRadioButton buttonToSelect)
|
||||
{
|
||||
if (!_buttons.Contains(buttonToSelect) || !buttonToSelect.IsEnabled) return;
|
||||
|
||||
SelectedButton = buttonToSelect;
|
||||
foreach (var btn in _buttons)
|
||||
{
|
||||
bool isNowSelected = (btn == SelectedButton);
|
||||
if (btn.IsSelected != isNowSelected) // 실제 상태 변경이 있을 때만
|
||||
{
|
||||
btn.IsSelected = isNowSelected; // 이 setter가 OnStateChanged를 호출
|
||||
// btn.OnClick?.Invoke(); // OnClick은 버튼 자체의 ExecuteClick에서 관리하는 것이 더 적절할 수 있음
|
||||
// 또는 선택 변경 시 항상 호출하고 싶다면 여기에 둠
|
||||
// btn.OnToggle?.Invoke(isNowSelected); // OnToggle은 IsSelected setter에서 OnToggleStateChanged로 대체 가능
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6099bb327827504c8c4e36c74c7c507
|
||||
7
Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs
Normal file
7
Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 툴바 구분선을 나타냅니다.
|
||||
/// </summary>
|
||||
public class ToolbarSeparator : IToolbarItem { }
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41943a25123704b4f82ec6417863d158
|
||||
16
Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs
Normal file
16
Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 일반적인 클릭 버튼입니다.
|
||||
/// </summary>
|
||||
public class ToolbarStandardButton : ToolbarButtonBase
|
||||
{
|
||||
public override void ExecuteClick()
|
||||
{
|
||||
if (IsEnabled && OnClick != null)
|
||||
{
|
||||
OnClick.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d7cc1da90c7117449ff98ba4600c3ce
|
||||
38
Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs
Normal file
38
Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
/// <summary>
|
||||
/// 클릭할 때마다 선택/해제 상태가 변경되는 토글 버튼입니다.
|
||||
/// </summary>
|
||||
public class ToolbarToggleButton : ToolbarButtonBase
|
||||
{
|
||||
public event Action<bool> OnToggleStateChanged; // IsSelected 변경 시 IsSelected 값을 전달하는 이벤트
|
||||
|
||||
private bool _isSelected;
|
||||
public bool IsSelected
|
||||
{
|
||||
get => _isSelected;
|
||||
set
|
||||
{
|
||||
if (_isSelected != value)
|
||||
{
|
||||
_isSelected = value;
|
||||
OnToggleStateChanged?.Invoke(_isSelected); // IsSelected 값과 함께 이벤트 발생
|
||||
NotifyStateChanged(); // 일반 상태 변경 이벤트도 발생
|
||||
}
|
||||
}
|
||||
}
|
||||
public Action<bool> OnToggle { get; set; }
|
||||
|
||||
public override void ExecuteClick()
|
||||
{
|
||||
if (IsEnabled)
|
||||
{
|
||||
IsSelected = !IsSelected; // IsSelected의 setter가 OnStateChanged를 호출
|
||||
OnClick?.Invoke(); // OnClick은 상태 변경과 별개로 클릭 시 항상 호출되도록 할 수 있음
|
||||
OnToggle?.Invoke(IsSelected); // 기존 OnToggle 로직 유지
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6407c881188c7c04c9cb4efb1dd7b4ce
|
||||
453
Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs
Normal file
453
Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs
Normal file
@@ -0,0 +1,453 @@
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UVC.Locale;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
public class ToolbarView : MonoBehaviour
|
||||
{
|
||||
public Toolbar ToolbarModel { get; private set; }
|
||||
|
||||
public GameObject standardButtonPrefab;
|
||||
public GameObject toggleButtonPrefab;
|
||||
public GameObject radioButtonPrefab;
|
||||
public GameObject expandableButtonPrefab;
|
||||
public GameObject separatorPrefab;
|
||||
public GameObject subMenuPanelPrefab;
|
||||
public GameObject tooltipPrefab; // 툴팁 UI 프리팹
|
||||
|
||||
private Transform toolbarContainer;
|
||||
// UI 요소와 모델을 매핑하여 상태 업데이트 시 사용
|
||||
private Dictionary<ToolbarButtonBase, GameObject> _modelToGameObjectMap = new Dictionary<ToolbarButtonBase, GameObject>();
|
||||
|
||||
private GameObject _activeTooltipInstance;
|
||||
private TextMeshProUGUI _tooltipTextElement;
|
||||
private RectTransform _tooltipRectTransform;
|
||||
|
||||
public void Initialize(Toolbar toolbarModel, Transform container)
|
||||
{
|
||||
ToolbarModel = toolbarModel;
|
||||
toolbarContainer = container;
|
||||
|
||||
// UI 레이아웃: toolbarContainer에 VerticalLayoutGroup 또는 HorizontalLayoutGroup 컴포넌트를 추가하고
|
||||
// 자식 크기 제어 (Child Force Expand 등) 옵션을 조정하면 UI 요소들이 자동으로 정렬됩니다.
|
||||
// 예: var layoutGroup = toolbarContainer.GetComponent<HorizontalLayoutGroup>();
|
||||
// if (layoutGroup == null) layoutGroup = toolbarContainer.gameObject.AddComponent<HorizontalLayoutGroup>();
|
||||
// layoutGroup.childControlHeight = true; layoutGroup.childControlWidth = false; // 예시 설정
|
||||
|
||||
RenderToolbar();
|
||||
|
||||
if (tooltipPrefab != null)
|
||||
{
|
||||
_activeTooltipInstance = Instantiate(tooltipPrefab, transform); // ToolbarView의 자식으로 생성 (Canvas 내 다른 곳이어도 됨)
|
||||
_tooltipTextElement = _activeTooltipInstance.GetComponentInChildren<TextMeshProUGUI>();
|
||||
_tooltipRectTransform = _activeTooltipInstance.GetComponent<RectTransform>();
|
||||
_activeTooltipInstance.SetActive(false); // 처음에는 숨김
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearToolbar()
|
||||
{
|
||||
foreach (var pair in _modelToGameObjectMap)
|
||||
{
|
||||
if (pair.Key != null)
|
||||
{
|
||||
pair.Key.OnStateChanged -= () => UpdateItemVisuals(pair.Key); // 이벤트 구독 해제
|
||||
if (pair.Key is ToolbarToggleButton toggleButton)
|
||||
{
|
||||
toggleButton.OnToggleStateChanged -= (isSelected) => UpdateToggleVisuals(toggleButton, isSelected);
|
||||
}
|
||||
}
|
||||
if (pair.Value != null)
|
||||
{
|
||||
// TooltipHandler 이벤트 구독 해제 (필요 시)
|
||||
TooltipHandler handler = pair.Value.GetComponent<TooltipHandler>();
|
||||
if (handler != null)
|
||||
{
|
||||
handler.OnPointerEnterAction = null;
|
||||
handler.OnPointerExitAction = null;
|
||||
}
|
||||
Destroy(pair.Value);
|
||||
}
|
||||
}
|
||||
_modelToGameObjectMap.Clear();
|
||||
_toggleGroups.Clear(); // 토글 그룹도 정리
|
||||
if (currentSubMenu != null) Destroy(currentSubMenu);
|
||||
HideTooltip(); // 툴바가 클리어될 때 툴팁도 숨김
|
||||
}
|
||||
|
||||
private void RenderToolbar()
|
||||
{
|
||||
ClearToolbar(); // 기존 UI 및 이벤트 구독 정리
|
||||
|
||||
if (ToolbarModel == null || ToolbarModel.Items == null) return;
|
||||
|
||||
foreach (var item in ToolbarModel.Items)
|
||||
{
|
||||
GameObject itemObj = null;
|
||||
if (item is ToolbarSeparator)
|
||||
{
|
||||
itemObj = Instantiate(separatorPrefab, toolbarContainer);
|
||||
}
|
||||
else if (item is ToolbarButtonBase buttonModel) // 모든 버튼 타입의 기본 처리
|
||||
{
|
||||
// 적절한 프리팹 선택
|
||||
if (buttonModel is ToolbarRadioButton) itemObj = Instantiate(radioButtonPrefab, toolbarContainer);
|
||||
else if (buttonModel is ToolbarToggleButton) itemObj = Instantiate(toggleButtonPrefab, toolbarContainer);
|
||||
else if (buttonModel is ToolbarExpandableButton) itemObj = Instantiate(expandableButtonPrefab, toolbarContainer);
|
||||
else if (buttonModel is ToolbarStandardButton) itemObj = Instantiate(standardButtonPrefab, toolbarContainer);
|
||||
// else // 다른 커스텀 버튼 타입이 있다면 추가
|
||||
|
||||
if (itemObj != null)
|
||||
{
|
||||
_modelToGameObjectMap[buttonModel] = itemObj;
|
||||
buttonModel.OnStateChanged += () => UpdateItemVisuals(buttonModel); // 모델 상태 변경 시 UI 업데이트 구독
|
||||
|
||||
// 초기 UI 설정 및 이벤트 바인딩
|
||||
SetupButtonVisualsAndInteractions(buttonModel, itemObj);
|
||||
|
||||
// 툴팁 핸들러 추가 및 설정
|
||||
if (!string.IsNullOrEmpty(buttonModel.TooltipKey))
|
||||
{
|
||||
TooltipHandler tooltipHandler = itemObj.GetComponent<TooltipHandler>();
|
||||
if (tooltipHandler == null) tooltipHandler = itemObj.AddComponent<TooltipHandler>();
|
||||
|
||||
tooltipHandler.TooltipKey = buttonModel.TooltipKey;
|
||||
tooltipHandler.OnPointerEnterAction = HandlePointerEnter;
|
||||
tooltipHandler.OnPointerExitAction = HandlePointerExit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePointerEnter(string tooltipKey, Vector3 mousePosition)
|
||||
{
|
||||
if (LocalizationManager.Instance != null && _tooltipTextElement != null)
|
||||
{
|
||||
string tooltipText = LocalizationManager.Instance.GetString(tooltipKey);
|
||||
if (string.IsNullOrEmpty(tooltipText) || tooltipText == $"[{tooltipKey}]") // 번역 실패 또는 키 그대로 반환 시
|
||||
{
|
||||
// 번역이 없거나 실패한 경우 툴팁을 표시하지 않거나, 기본 메시지를 표시할 수 있습니다.
|
||||
// 여기서는 표시하지 않도록 합니다.
|
||||
HideTooltip();
|
||||
return;
|
||||
}
|
||||
ShowTooltip(tooltipText, mousePosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePointerExit()
|
||||
{
|
||||
HideTooltip();
|
||||
}
|
||||
|
||||
private void ShowTooltip(string text, Vector3 mousePosition)
|
||||
{
|
||||
if (_activeTooltipInstance == null || _tooltipTextElement == null) return;
|
||||
|
||||
_tooltipTextElement.text = text;
|
||||
_activeTooltipInstance.SetActive(true);
|
||||
|
||||
// 툴팁 위치 설정 (마우스 커서 기준, 화면 가장자리 넘어가지 않도록 조정 필요)
|
||||
// Canvas Render Mode에 따라 위치 계산 방식이 달라질 수 있습니다.
|
||||
// Screen Space - Overlay 예시:
|
||||
if (_tooltipRectTransform != null)
|
||||
{
|
||||
// TextMeshPro의 preferredWidth/Height를 사용하여 크기 조절
|
||||
_tooltipTextElement.ForceMeshUpdate(); // 텍스트 변경 후 메시 업데이트 강제
|
||||
Vector2 textSize = _tooltipTextElement.GetRenderedValues(false);
|
||||
Vector2 padding = new Vector2(10, 5); // 툴팁 내부 여백
|
||||
_tooltipRectTransform.sizeDelta = textSize + padding * 2;
|
||||
|
||||
|
||||
// 화면 가장자리 처리 (간단한 예시)
|
||||
Vector2 localPoint;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
transform.root as RectTransform, // Canvas의 최상위 RectTransform
|
||||
mousePosition,
|
||||
transform.root.GetComponent<Canvas>().worldCamera, // Screen Space - Camera 경우 필요
|
||||
out localPoint
|
||||
);
|
||||
|
||||
// 툴팁을 마우스 오른쪽 아래에 표시 (오프셋 조정 가능)
|
||||
_tooltipRectTransform.localPosition = localPoint + new Vector2(_tooltipRectTransform.sizeDelta.x * 0.5f + 10f, -_tooltipRectTransform.sizeDelta.y * 0.5f - 5f);
|
||||
|
||||
|
||||
// 화면 경계 체크 및 위치 조정 (더 정교한 로직 필요)
|
||||
Vector3[] corners = new Vector3[4];
|
||||
_tooltipRectTransform.GetWorldCorners(corners);
|
||||
float screenWidth = Screen.width;
|
||||
float screenHeight = Screen.height;
|
||||
|
||||
// 오른쪽 경계 넘어감
|
||||
if (corners[2].x > screenWidth)
|
||||
{
|
||||
Vector3 currentPos = _tooltipRectTransform.position;
|
||||
currentPos.x -= (corners[2].x - screenWidth);
|
||||
_tooltipRectTransform.position = currentPos;
|
||||
}
|
||||
// 왼쪽 경계 넘어감
|
||||
if (corners[0].x < 0)
|
||||
{
|
||||
Vector3 currentPos = _tooltipRectTransform.position;
|
||||
currentPos.x -= corners[0].x;
|
||||
_tooltipRectTransform.position = currentPos;
|
||||
}
|
||||
// 아래쪽 경계 넘어감 (툴팁을 위로 표시하도록 변경 가능)
|
||||
if (corners[0].y < 0)
|
||||
{
|
||||
Vector3 currentPos = _tooltipRectTransform.position;
|
||||
currentPos.y -= corners[0].y; // 위로 올림
|
||||
// 또는 마우스 위쪽으로 위치 변경
|
||||
// _tooltipRectTransform.localPosition = localPoint + new Vector2(_tooltipRectTransform.sizeDelta.x * 0.5f + 10f, _tooltipRectTransform.sizeDelta.y * 0.5f + 5f);
|
||||
_tooltipRectTransform.position = currentPos;
|
||||
}
|
||||
// 위쪽 경계 넘어감
|
||||
if (corners[1].y > screenHeight)
|
||||
{
|
||||
Vector3 currentPos = _tooltipRectTransform.position;
|
||||
currentPos.y -= (corners[1].y - screenHeight);
|
||||
_tooltipRectTransform.position = currentPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HideTooltip()
|
||||
{
|
||||
if (_activeTooltipInstance != null)
|
||||
{
|
||||
_activeTooltipInstance.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 버튼 모델과 게임 오브젝트를 받아 초기 시각적 요소 설정 및 UI 상호작용을 연결합니다.
|
||||
private void SetupButtonVisualsAndInteractions(ToolbarButtonBase model, GameObject itemObj)
|
||||
{
|
||||
// 공통 UI 요소 업데이트 (Text, Icon, Enabled)
|
||||
UpdateCommonButtonVisuals(model, itemObj);
|
||||
|
||||
// 타입별 UI 요소 및 이벤트 설정
|
||||
if (model is ToolbarRadioButton radioModel)
|
||||
{
|
||||
Toggle toggle = itemObj.GetComponent<Toggle>();
|
||||
if (toggle != null)
|
||||
{
|
||||
ToggleGroup toggleGroup = GetOrCreateToggleGroup(radioModel.GroupName);
|
||||
toggle.group = toggleGroup;
|
||||
toggle.SetIsOnWithoutNotify(radioModel.IsSelected); // 초기 상태 설정 (이벤트 발생 방지)
|
||||
toggle.onValueChanged.AddListener((isSelected) =>
|
||||
{
|
||||
// UI에서 사용자가 직접 토글한 경우 모델 업데이트
|
||||
// 중요: 라디오 버튼은 그룹에 의해 선택이 관리되므로, isSelected가 true일 때만 모델 업데이트 요청
|
||||
if (isSelected) radioModel.ExecuteClick(); // 모델의 ExecuteClick -> RadioGroup.SetSelected 호출
|
||||
});
|
||||
// IsSelected 변경은 OnStateChanged를 통해 UpdateItemVisuals에서 처리되거나,
|
||||
// 좀 더 명시적인 OnToggleStateChanged 이벤트를 사용할 수 있습니다.
|
||||
radioModel.OnToggleStateChanged += (isSelected) => UpdateToggleVisuals(radioModel, isSelected);
|
||||
}
|
||||
}
|
||||
else if (model is ToolbarToggleButton toggleModel)
|
||||
{
|
||||
Toggle toggle = itemObj.GetComponent<Toggle>();
|
||||
if (toggle != null)
|
||||
{
|
||||
toggle.SetIsOnWithoutNotify(toggleModel.IsSelected);
|
||||
toggle.onValueChanged.AddListener((isSelected) =>
|
||||
{
|
||||
toggleModel.ExecuteClick(); // 모델의 ExecuteClick이 IsSelected를 변경하고 OnStateChanged 호출
|
||||
});
|
||||
toggleModel.OnToggleStateChanged += (isSelected) => UpdateToggleVisuals(toggleModel, isSelected);
|
||||
}
|
||||
}
|
||||
else if (model is ToolbarExpandableButton expandableModel)
|
||||
{
|
||||
Button uiButton = itemObj.GetComponent<Button>();
|
||||
if (uiButton != null)
|
||||
{
|
||||
uiButton.onClick.AddListener(() =>
|
||||
{
|
||||
expandableModel.ExecuteClick();
|
||||
ToggleSubMenu(expandableModel, itemObj); // itemObj 전달하여 위치 기준으로 삼기
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (model is ToolbarStandardButton standardModel)
|
||||
{
|
||||
Button uiButton = itemObj.GetComponent<Button>();
|
||||
if (uiButton != null)
|
||||
{
|
||||
uiButton.onClick.AddListener(() =>
|
||||
{
|
||||
standardModel.ExecuteClick();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 모델의 상태가 변경되었을 때 호출되어 모든 관련 UI를 업데이트합니다.
|
||||
private void UpdateItemVisuals(ToolbarButtonBase model)
|
||||
{
|
||||
if (_modelToGameObjectMap.TryGetValue(model, out GameObject itemObj))
|
||||
{
|
||||
UpdateCommonButtonVisuals(model, itemObj); // 공통 부분 업데이트
|
||||
|
||||
// 타입별 특화된 부분 업데이트 (예: Toggle의 isOn 상태)
|
||||
if (model is ToolbarToggleButton tb) // ToolbarRadioButton도 여기에 해당
|
||||
{
|
||||
Toggle toggle = itemObj.GetComponent<Toggle>();
|
||||
if (toggle != null && toggle.isOn != tb.IsSelected) // UI와 모델 상태가 다를 때만 업데이트
|
||||
{
|
||||
toggle.SetIsOnWithoutNotify(tb.IsSelected);
|
||||
}
|
||||
}
|
||||
// 다른 버튼 타입에 대한 추가적인 시각적 업데이트 로직
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 토글 버튼/라디오 버튼의 IsSelected 상태가 모델에서 변경되었을 때 호출됩니다.
|
||||
private void UpdateToggleVisuals(ToolbarToggleButton model, bool isSelected)
|
||||
{
|
||||
if (_modelToGameObjectMap.TryGetValue(model, out GameObject itemObj))
|
||||
{
|
||||
Toggle toggle = itemObj.GetComponent<Toggle>();
|
||||
if (toggle != null && toggle.isOn != isSelected)
|
||||
{
|
||||
toggle.SetIsOnWithoutNotify(isSelected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 공통 버튼 시각적 요소(텍스트, 아이콘, 활성화 상태)를 업데이트합니다.
|
||||
private void UpdateCommonButtonVisuals(ToolbarButtonBase model, GameObject itemObj)
|
||||
{
|
||||
// 프리팹 구조에 대한 가정:
|
||||
// - 텍스트는 TextMeshProUGUI 컴포넌트를 가진 자식 오브젝트에 표시됩니다.
|
||||
// - 아이콘은 "Icon"이라는 이름의 자식 오브젝트에 Image 컴포넌트로 표시됩니다.
|
||||
// 이러한 구조는 프로젝트의 프리팹 표준에 맞게 조정해야 합니다.
|
||||
|
||||
TextMeshProUGUI buttonTextComponent = itemObj.GetComponentInChildren<TextMeshProUGUI>(true);
|
||||
if (buttonTextComponent != null)
|
||||
{
|
||||
if (LocalizationManager.Instance != null && !string.IsNullOrEmpty(model.Text))
|
||||
{
|
||||
// model.Text에는 이제 다국어 키가 저장되어 있습니다.
|
||||
buttonTextComponent.text = LocalizationManager.Instance.GetString(model.Text);
|
||||
}
|
||||
else
|
||||
{
|
||||
// LocalizationManager가 없거나 Text(키)가 비어있는 경우, 키를 그대로 표시하거나 기본값 처리
|
||||
buttonTextComponent.text = model.Text;
|
||||
}
|
||||
}
|
||||
|
||||
Transform iconTransform = itemObj.transform.Find("Icon"); // 프리팹에 "Icon" 자식 오브젝트가 있다고 가정
|
||||
if (iconTransform != null)
|
||||
{
|
||||
Image buttonIcon = iconTransform.GetComponent<Image>();
|
||||
if (buttonIcon != null)
|
||||
{
|
||||
buttonIcon.sprite = model.Icon;
|
||||
buttonIcon.gameObject.SetActive(model.Icon != null);
|
||||
}
|
||||
}
|
||||
|
||||
// 상호작용 가능 상태 업데이트
|
||||
Selectable selectable = itemObj.GetComponent<Selectable>(); // Button, Toggle 등
|
||||
if (selectable != null)
|
||||
{
|
||||
selectable.interactable = model.IsEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Dictionary<string, ToggleGroup> _toggleGroups = new Dictionary<string, ToggleGroup>();
|
||||
private ToggleGroup GetOrCreateToggleGroup(string groupName)
|
||||
{
|
||||
if (!_toggleGroups.TryGetValue(groupName, out ToggleGroup group))
|
||||
{
|
||||
GameObject groupObj = new GameObject($"ToggleGroup_{groupName}");
|
||||
groupObj.transform.SetParent(toolbarContainer);
|
||||
group = groupObj.AddComponent<ToggleGroup>();
|
||||
group.allowSwitchOff = false; // 라디오 버튼 그룹은 일반적으로 하나는 선택되어 있도록 함
|
||||
_toggleGroups.Add(groupName, group);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private GameObject currentSubMenu = null;
|
||||
// expandableButtonObj는 확장 메뉴의 위치를 잡기 위해 사용될 수 있습니다.
|
||||
private void ToggleSubMenu(ToolbarExpandableButton expandableButton, GameObject expandableButtonObj)
|
||||
{
|
||||
if (currentSubMenu != null)
|
||||
{
|
||||
Destroy(currentSubMenu);
|
||||
currentSubMenu = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (subMenuPanelPrefab == null || expandableButton.SubButtons.Count == 0) return;
|
||||
|
||||
currentSubMenu = Instantiate(subMenuPanelPrefab, transform); // ToolbarView의 자식으로 생성 후 위치 조정
|
||||
// 위치 조정 로직: expandableButtonObj의 위치를 기준으로 currentSubMenu의 RectTransform을 조정합니다.
|
||||
// 예: currentSubMenu.transform.position = expandableButtonObj.transform.position + offset;
|
||||
|
||||
RectTransform panelRect = currentSubMenu.GetComponent<RectTransform>();
|
||||
// 하위 메뉴 패널에 LayoutGroup이 있다면 자식 버튼들이 자동으로 정렬됩니다.
|
||||
|
||||
foreach (var subItemBase in expandableButton.SubButtons)
|
||||
{
|
||||
if (subItemBase is ToolbarButtonBase subItem) // 모든 하위 아이템은 ToolbarButtonBase라고 가정
|
||||
{
|
||||
// 하위 버튼도 적절한 프리팹을 사용해야 합니다. 여기서는 standardButtonPrefab을 예시로 사용합니다.
|
||||
// 실제로는 subItem의 타입에 따라 다른 프리팹을 선택할 수 있습니다.
|
||||
GameObject subButtonObj = Instantiate(standardButtonPrefab, panelRect); // 패널의 자식으로 생성
|
||||
|
||||
// 하위 버튼의 시각적 요소 설정 및 상호작용 연결
|
||||
UpdateCommonButtonVisuals(subItem, subButtonObj); // 공통 시각 요소 업데이트
|
||||
|
||||
Button subUiButton = subButtonObj.GetComponent<Button>();
|
||||
if (subUiButton != null)
|
||||
{
|
||||
subUiButton.interactable = subItem.IsEnabled; // 상호작용 상태 설정
|
||||
subUiButton.onClick.AddListener(() =>
|
||||
{
|
||||
expandableButton.SelectSubButton(subItem); // 모델 업데이트 및 주 버튼 외형 변경 요청
|
||||
// 주 버튼 UI는 expandableButton의 OnStateChanged 이벤트에 의해 자동으로 업데이트됩니다.
|
||||
Destroy(currentSubMenu);
|
||||
currentSubMenu = null;
|
||||
});
|
||||
}
|
||||
|
||||
// 하위 버튼 툴팁 처리
|
||||
if (!string.IsNullOrEmpty(subItem.TooltipKey))
|
||||
{
|
||||
TooltipHandler tooltipHandler = subButtonObj.GetComponent<TooltipHandler>();
|
||||
if (tooltipHandler == null) tooltipHandler = subButtonObj.AddComponent<TooltipHandler>();
|
||||
|
||||
tooltipHandler.TooltipKey = subItem.TooltipKey;
|
||||
tooltipHandler.OnPointerEnterAction = HandlePointerEnter;
|
||||
tooltipHandler.OnPointerExitAction = HandlePointerExit;
|
||||
}
|
||||
|
||||
// 하위 버튼 모델의 OnStateChanged도 구독하여 하위 버튼 자체의 상태 변경(예: 텍스트)도 반영할 수 있습니다.
|
||||
// subItem.OnStateChanged += () => UpdateCommonButtonVisuals(subItem, subButtonObj);
|
||||
// _modelToGameObjectMap에 하위 버튼도 추가하여 ClearToolbar에서 정리되도록 해야 합니다. (선택적 확장)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// 씬 전환 등으로 ToolbarView가 파괴될 때 모든 이벤트 구독 해제
|
||||
ClearToolbar();
|
||||
if (_activeTooltipInstance != null)
|
||||
{
|
||||
Destroy(_activeTooltipInstance); // 툴팁 인스턴스도 파괴
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60240c8d04420604681084344d3a0253
|
||||
26
Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs
Normal file
26
Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace UVC.UI.ToolBar
|
||||
{
|
||||
public class TooltipHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
|
||||
{
|
||||
public System.Action<string, Vector3> OnPointerEnterAction; // 툴팁 내용(키), 마우스 위치
|
||||
public System.Action OnPointerExitAction;
|
||||
public string TooltipKey { get; set; }
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(TooltipKey) && gameObject.GetComponent<Selectable>()?.interactable == true) // 버튼이 활성화 상태일 때만
|
||||
{
|
||||
OnPointerEnterAction?.Invoke(TooltipKey, Input.mousePosition);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
OnPointerExitAction?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 266dd70132eff3d4eb32c995c009634a
|
||||
Reference in New Issue
Block a user