Component List 개발 중

This commit is contained in:
logonkhi
2025-08-08 18:33:29 +09:00
parent 3297a5d1f3
commit 165c3a709f
60 changed files with 7809 additions and 3072 deletions

View File

@@ -20,68 +20,17 @@ namespace UVC.UI.Menu
/// Inspector에서 <see cref="TopMenuController"/>와 <see cref="TopMenuView"/> 추가해서 사용합니다.
/// </summary>
/// <example>
/// 다음은 TopMenuController를 상속받아 특정 기능을 확장하는 예제입니다.
/// 다음은 TopMenuController를 사용해 메뉴를 구성하는 예제 입니다.
/// <code>
/// public class CustomTopMenuController : TopMenuController
/// private TopMenuController topMenu;
///
/// // 예: '도움말' 메뉴 추가
/// topMenu.AddMenuItem(new MenuItemData("help", "menu_help", subMenuItems: new List<MenuItemData>;
/// {
/// protected override void InitializeMenuItems()
/// {
/// // 기본 메뉴 아이템 초기화 로직 호출
/// base.InitializeMenuItems();
///
/// // 기존 모델에 새로운 메뉴 아이템 추가 또는 수정
/// // 예: '도움말' 메뉴 추가
/// model.MenuItems.Add(new MenuItemData("help", "menu_help", subMenuItems: new List<MenuItemData>;
/// {
/// new MenuItemData("help_about", "menu_help_about", new DebugLogCommand("도움말 > 정보 선택됨"))
/// }));
///
/// // 변경된 모델을 기반으로 뷰를 다시 생성하거나 업데이트해야 할 수 있습니다.
/// // (이미 Start 메서드에서 CreateMenuItems가 호출되므로, InitializeMenuItems 시점에서는 모델만 수정)
/// ULog.Debug("CustomTopMenuController: '도움말' 메뉴가 추가되었습니다.");
/// }
///
/// protected override void HandleMenuItemClicked(MenuItemData clickedItemData)
/// {
/// // 기본 클릭 처리 로직 호출
/// base.HandleMenuItemClicked(clickedItemData);
///
/// // 특정 메뉴 아이템에 대한 추가적인 커스텀 로직 수행
/// if (clickedItemData.ItemId == "file_exit")
/// {
/// ULog.Debug("CustomTopMenuController: 애플리케이션 종료 메뉴가 선택되었습니다. 추가 확인 로직을 여기에 넣을 수 있습니다.");
/// // 예: 사용자에게 정말 종료할 것인지 확인하는 팝업 표시 등
/// }
/// }
///
/// // 새로운 기능을 추가할 수도 있습니다.
/// public void AddCustomMenuOption(string parentItemId, MenuItemData newItem)
/// {
/// if (model == null || model.MenuItems == null) return;
///
/// MenuItemData parentItem = FindMenuItemRecursive(model.MenuItems, parentItemId);
/// if (parentItem != null)
/// {
/// if (parentItem.IsSeparator)
/// {
/// ULog.Warning($"구분선('{parentItemId}')에는 하위 메뉴를 추가할 수 없습니다.");
/// return;
/// }
/// parentItem.AddSubMenuItem(newItem);
/// ULog.Debug($"'{parentItemId}'에 새로운 하위 메뉴 '{newItem.ItemId}'가 추가되었습니다.");
///
/// // 중요: 모델 변경 후에는 뷰를 업데이트해야 합니다.
/// // 예를 들어, 메뉴를 전부 다시 그리거나 특정 부분만 업데이트하는 메서드를 호출합니다.
/// // view.ClearMenuItems();
/// // view.CreateMenuItems(model.MenuItems, view.MenuContainer);
/// // 또는 더 정교한 뷰 업데이트 메서드가 필요할 수 있습니다.
/// }
/// else
/// {
/// ULog.Warning($"ID가 '{parentItemId}'인 부모 메뉴 아이템을 찾을 수 없습니다.");
/// }
/// }
/// }
/// new MenuItemData("help_about", "menu_help_about", new DebugLogCommand("도움말 > 정보 선택됨"))
/// }));
///
/// topMenu.Initialize(); // 메뉴 초기화 및 생성 요청
/// </code>
/// </example>
public class TopMenuController : MonoBehaviour
@@ -104,6 +53,8 @@ namespace UVC.UI.Menu
/// </summary>
protected LocalizationManager _locManager;
protected bool isInitialized = false;
/// <summary>
/// MonoBehaviour의 Awake 메시지입니다. 스크립트 인스턴스가 로드될 때 호출됩니다.
/// 주로 <see cref="view"/> 컴포넌트를 찾는 데 사용됩니다.
@@ -120,7 +71,11 @@ namespace UVC.UI.Menu
view = GetComponentInChildren<TopMenuView>();
}
// view가 여전히 null이라면, Start 메서드에서 오류를 기록할 것입니다.
// 메뉴 데이터 모델 인스턴스 생성
model = new TopMenuModel();
// 다국어 관리자 인스턴스 가져오기
_locManager = LocalizationManager.Instance;
}
/// <summary>
@@ -130,18 +85,12 @@ namespace UVC.UI.Menu
/// </summary>
protected virtual void Start()
{
// 메뉴 데이터 모델 인스턴스 생성
model = new TopMenuModel();
// 다국어 관리자 인스턴스 가져오기
_locManager = LocalizationManager.Instance;
// View 컴포넌트가 할당되었는지 확인
if (view == null)
{
ULog.Error("TopMenuView가 Inspector에서 할당되지 않았거나 찾을 수 없습니다. TopMenuController가 정상적으로 작동하지 않습니다.");
return; // View가 없으면 더 이상 진행할 수 없음
}
// LocalizationManager 인스턴스 확인
if (_locManager == null)
{
@@ -149,24 +98,6 @@ namespace UVC.UI.Menu
// _locManager가 null이어도 메뉴 구조 자체는 생성될 수 있도록 계속 진행합니다.
// TopMenuView와 이 클래스의 다른 부분에서 _locManager null 체크를 통해 안전하게 처리합니다.
}
// 메뉴 아이템 데이터 초기화 (모델 채우기)
InitializeMenuItems();
// View에 기존 메뉴 아이템들을 지우도록 요청
view.ClearMenuItems();
// View에 현재 모델 데이터를 기반으로 메뉴 UI를 생성하도록 요청
// view.MenuContainer는 TopMenuView에서 메뉴 UI 요소들이 배치될 부모 Transform을 가리킵니다.
view.CreateMenuItems(model.MenuItems, view.menuContainer);
// View에서 발생하는 메뉴 아이템 클릭 이벤트에 대한 핸들러 등록
view.OnMenuItemClicked += HandleMenuItemClicked;
// LocalizationManager가 존재하고, 언어 변경 이벤트를 지원한다면 핸들러 등록
if (_locManager != null)
{
_locManager.OnLanguageChanged += HandleLanguageChanged;
}
}
/// <summary>
@@ -188,64 +119,82 @@ namespace UVC.UI.Menu
}
/// <summary>
/// 메뉴 아이템 데이터를 초기화하고 <see cref="model"/>에 추가합니다.
/// 이 메서드에서 메뉴의 전체 구조(항목, 하위 항목, 구분선, 연결된 명령 등)를 정의합니다.
/// 상속 클래스에서 이 메서드를 오버라이드하여 메뉴 구성을 변경하거나 확장할 수 있습니다.
/// 모델 초기화, <see cref="LocalizationManager"/> 인스턴스 가져오기, 메뉴 아이템 데이터 설정,
/// View에 메뉴 생성 요청, 이벤트 핸들러 등록 등의 주요 초기화 작업을 수행합니다.
/// </summary>
protected virtual void InitializeMenuItems()
public virtual void Initialize()
{
// 기존 메뉴 아이템 목록을 비웁니다.
model.MenuItems.Clear();
if (isInitialized) {
Debug.LogWarning("TopMenuController가 이미 초기화되었습니다. 중복 초기화를 방지합니다.");
return;
}
// "파일" 메뉴 및 하위 메뉴들 정의
model.MenuItems.Add(new MenuItemData("file", "menu_file", subMenuItems: new List<MenuItemData>
{
new MenuItemData("file_new", "menu_file_new", subMenuItems: new List<MenuItemData>
{
new MenuItemData("file_new_project", "menu_file_new_project", new DebugLogCommand("새 프로젝트 선택됨 (Command 실행)")),
new MenuItemData("file_new_file", "menu_file_new_file",
new ActionCommand(() => Debug.Log("[SampleProject] 새 파일 선택됨")))
}),
new MenuItemData("file_open", "menu_file_open",
new ActionCommand<string>((path) => Debug.Log($"[SampleProject] 파일 열기 선택됨: {path}"), "sample.txt"),
commandParameter: "another_sample.txt", // 이 파라미터가 HandleMenuItemClicked에서 사용됨
isEnabled: false), // "파일 열기"는 비활성화 상태로 시작
MenuItemData.CreateSeparator("file_sep1"), // 구분선 추가
new MenuItemData("file_save", "menu_file_save", command: new DebugLogCommand("저장 선택됨 (Command 실행)") , subMenuItems: new List<MenuItemData>
{
new MenuItemData("file_save_as", "menu_file_save_as", new DebugLogCommand("다른 이름으로 저장 선택됨 (Command 실행)"))
}),
MenuItemData.CreateSeparator("file_sep2"), // 또 다른 구분선 추가
new MenuItemData("file_exit", "menu_file_exit", new QuitApplicationCommand()) // 애플리케이션 종료 명령 연결
}));
model.MenuItems.Add(new MenuItemData("Playback", "Playback", new PlaybackCommand()));
// pool 로그
model.MenuItems.Add(new MenuItemData("log", "Log", subMenuItems: new List<MenuItemData>
{
new MenuItemData("dataArray", "DataArray", new ActionCommand(() => Debug.Log($"DataArrayPool stats: {DataArrayPool.GetStats()}"))),
new MenuItemData("dataObject", "DataObjet", new ActionCommand(() => Debug.Log($"DataObjectPool stats: {DataObjectPool.GetStats()}"))),
new MenuItemData("agv", "AGVPool", new ActionCommand(() => Debug.Log($"AGVPool stats: {AGVManager.Instance.AGVPool.GetStats()}"))),
}));
model.MenuItems.Add(new MenuItemData("modal", "모달", subMenuItems: new List<MenuItemData>
{
new MenuItemData("alert", "Alert", new ActionCommand(async () => {
await Alert.Show("알림", "이것은 간단한 알림 메시지입니다.");
await Alert.Show("경고", "데이터를 저장할 수 없습니다.", "알겠습니다");
await Alert.Show("error", "error_network_not", "button_retry");
})),
new MenuItemData("confirm", "Confirm", new ActionCommand(async () => {
bool result = await Confirm.Show("확인", "이것은 간단한 알림 메시지입니다.");
ULog.Debug($"사용자가 확인 버튼을 눌렀나요? {result}");
result = await Confirm.Show("경고", "데이터를 저장할 수 없습니다.", "알겠습니다~~~~", "아니요");
ULog.Debug($"사용자가 알림을 확인했나요? {result}");
result = await Confirm.Show("error", "error_network_not", "button_retry", "button_cancel");
ULog.Debug($"사용자가 네트워크 오류 알림을 확인했나요? {result}");
}))
}));
// View에 기존 메뉴 아이템들을 지우도록 요청
view.ClearMenuItems();
// View에 현재 모델 데이터를 기반으로 메뉴 UI를 생성하도록 요청
// view.MenuContainer는 TopMenuView에서 메뉴 UI 요소들이 배치될 부모 Transform을 가리킵니다.
view.CreateMenuItems(model.MenuItems, view.menuContainer);
model.MenuItems.Add(new MenuItemData("Settings", "Settings", new SettingOpenCommand()));
// View에서 발생하는 메뉴 아이템 클릭 이벤트에 대한 핸들러 등록
view.OnMenuItemClicked += HandleMenuItemClicked;
// LocalizationManager가 존재하고, 언어 변경 이벤트를 지원한다면 핸들러 등록
if (_locManager != null)
{
_locManager.OnLanguageChanged += HandleLanguageChanged;
}
isInitialized = true;
}
/// <summary>
/// 메뉴 아이템을 추가합니다.
/// </summary>
/// <param name="newItem">추가할 아이템</param>
public void AddMenuItem(MenuItemData newItem)
{
if (model == null || model.MenuItems == null)
{
ULog.Warning("모델이 초기화되지 않아 메뉴 아이템을 추가할 수 없습니다.");
return;
}
// 모델에 새 메뉴 아이템 추가
model.MenuItems.Add(newItem);
ULog.Debug($"새로운 메뉴 아이템 '{newItem.ItemId}'가 모델에 추가되었습니다.");
}
/// <summary>
/// 추가 된 아이템을 제거 합니다.
/// </summary>
/// <param name="itemId">삭제 할 아이템의 ID</param>
public void RemoveMenuItem(string itemId)
{
if (model == null || model.MenuItems == null)
{
ULog.Warning("모델이 초기화되지 않아 메뉴 아이템을 제거할 수 없습니다.");
return;
}
// 모델에서 해당 ID를 가진 메뉴 아이템을 재귀적으로 검색
MenuItemData targetItem = FindMenuItemRecursive(model.MenuItems, itemId);
if (targetItem != null)
{
// 구분선은 제거할 수 없음
if (targetItem.IsSeparator)
{
ULog.Warning($"구분선('{itemId}')은 제거할 수 없습니다. 작업이 무시됩니다.");
return;
}
// 모델에서 아이템 제거
model.MenuItems.Remove(targetItem);
ULog.Debug($"ID가 '{itemId}'인 메뉴 아이템이 모델에서 제거되었습니다.");
}
else
{
ULog.Warning($"ID가 '{itemId}'인 메뉴 아이템을 모델에서 찾을 수 없어 제거할 수 없습니다.");
}
}
/// <summary>
/// <see cref="TopMenuView.OnMenuItemClicked"/> 이벤트가 발생했을 때 호출되는 핸들러입니다.
/// 클릭된 메뉴 아이템(<paramref name="clickedItemData"/>)의 유효성을 검사하고,