단축키, UndoRedo 개발중
This commit is contained in:
22
Assets/Scripts/UVC/UI/Commands/IUndoableCommand.cs
Normal file
22
Assets/Scripts/UVC/UI/Commands/IUndoableCommand.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
#nullable enable
|
||||
namespace UVC.UI.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// Undo/Redo 가능한 Command 인터페이스
|
||||
/// ICommand + IUndoable 통합
|
||||
/// </summary>
|
||||
public interface IUndoableCommand : ICommand, IUndoable
|
||||
{
|
||||
/// <summary>작업 설명 (UI 표시용, 예: "객체 복제", "Node 삭제")</summary>
|
||||
string Description { get; }
|
||||
|
||||
/// <summary>다시 실행</summary>
|
||||
void Redo();
|
||||
|
||||
/// <summary>연속 동작 병합 가능 여부 (예: 연속 Transform 변경)</summary>
|
||||
bool CanMerge(IUndoableCommand other);
|
||||
|
||||
/// <summary>연속 동작 병합</summary>
|
||||
void Merge(IUndoableCommand other);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/UVC/UI/Commands/IUndoableCommand.cs.meta
Normal file
2
Assets/Scripts/UVC/UI/Commands/IUndoableCommand.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 269f16afecf878047ae53d4bac753753
|
||||
@@ -3,21 +3,23 @@ using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UVC.UI.Modal.DatePicker;
|
||||
|
||||
namespace UVC.UI.List.Tree
|
||||
{
|
||||
/// <summary>
|
||||
/// 트리 구조의 리스트를 관리하고 제어하는 클래스입니다.
|
||||
///
|
||||
///
|
||||
/// 주요 기능:
|
||||
/// - 계층 구조 아이템의 추가/제거 관리
|
||||
/// - 단일 및 다중 선택 지원 (파일 탐색기와 동일)
|
||||
/// - 키보드 입력(Delete, 화살표, Ctrl, Shift) 처리
|
||||
/// - 드래그 & 드롭 기능 지원
|
||||
/// - 선택 상태 변경 이벤트 제공
|
||||
///
|
||||
///
|
||||
/// 선택 동작:
|
||||
/// - 클릭: 한 항목 선택
|
||||
/// - Ctrl+클릭: 여러 항목 선택 (기존 선택 유지)
|
||||
@@ -135,6 +137,12 @@ namespace UVC.UI.List.Tree
|
||||
/// </summary>
|
||||
public Action<TreeListItemData, bool>? OnItemVisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 아이템 더블클릭 이벤트 (data)
|
||||
/// TreeListItem이 더블클릭될 때 호출됩니다.
|
||||
/// </summary>
|
||||
public Action<TreeListItemData>? OnItemDoubleClicked;
|
||||
|
||||
/// <summary>
|
||||
/// 현재 선택된 아이템 목록 (읽기 전용)
|
||||
/// </summary>
|
||||
@@ -320,6 +328,9 @@ namespace UVC.UI.List.Tree
|
||||
|
||||
protected void Update()
|
||||
{
|
||||
// 입력 필드에 포커스가 있으면 키보드 입력 무시
|
||||
if (IsInputFieldFocused()) return;
|
||||
|
||||
// Escape 키 입력 감지 - 선택 해제
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
{
|
||||
@@ -355,6 +366,36 @@ namespace UVC.UI.List.Tree
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 입력 필드에 포커스가 있는지 확인합니다.
|
||||
/// </summary>
|
||||
private bool IsInputFieldFocused()
|
||||
{
|
||||
var eventSystem = EventSystem.current;
|
||||
if (eventSystem == null) return false;
|
||||
|
||||
var selected = eventSystem.currentSelectedGameObject;
|
||||
if (selected == null) return false;
|
||||
|
||||
// TMP_InputField 확인 (자기 자신 및 부모 계층에서 검색)
|
||||
var tmpInput = selected.GetComponent<TMP_InputField>();
|
||||
if (tmpInput == null)
|
||||
{
|
||||
tmpInput = selected.GetComponentInParent<TMP_InputField>();
|
||||
}
|
||||
if (tmpInput != null && tmpInput.isFocused) return true;
|
||||
|
||||
// Legacy InputField 확인 (자기 자신 및 부모 계층에서 검색)
|
||||
var legacyInput = selected.GetComponent<UnityEngine.UI.InputField>();
|
||||
if (legacyInput == null)
|
||||
{
|
||||
legacyInput = selected.GetComponentInParent<UnityEngine.UI.InputField>();
|
||||
}
|
||||
if (legacyInput != null && legacyInput.isFocused) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// View 등록(데이터↔View 맵). Init 시점에 호출됩니다.
|
||||
/// </summary>
|
||||
@@ -444,9 +485,11 @@ namespace UVC.UI.List.Tree
|
||||
// 디버그 로그
|
||||
//Debug.Log($"Delete key pressed. Removing {itemsToDelete.Count} selected item(s).");
|
||||
|
||||
// 각 선택된 아이템을 삭제
|
||||
// 각 선택된 아이템에 대해 삭제 이벤트 발생 후 삭제
|
||||
foreach (var item in itemsToDelete)
|
||||
{
|
||||
// 삭제 전 이벤트 발생 (View 업데이트 + 외부에서 연관 데이터 정리 가능)
|
||||
NotifyDataChanged(item, ChangedType.Delete, item);
|
||||
DeleteItem(item);
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,16 @@ namespace UVC.UI.List.Tree
|
||||
|
||||
protected VerticalLayoutGroup? childRootLayoutGroup = null;
|
||||
|
||||
/// <summary>
|
||||
/// 마지막 클릭 시간 (더블클릭 감지용)
|
||||
/// </summary>
|
||||
protected float _lastClickTime = 0f;
|
||||
|
||||
/// <summary>
|
||||
/// 더블클릭 감지 시간 간격 (초)
|
||||
/// </summary>
|
||||
protected const float DoubleClickThreshold = 0.3f;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 초기화 (Initialization)
|
||||
@@ -456,11 +466,23 @@ namespace UVC.UI.List.Tree
|
||||
/// - TreeList의 OnItemClickAction 이벤트 실행
|
||||
/// - Ctrl/Shift 상태를 읽어 TreeList에 전달
|
||||
/// (일반/토글/범위 선택)
|
||||
/// - 더블클릭 감지 시 OnItemDoubleClicked 이벤트 실행
|
||||
/// </summary>
|
||||
protected void OnItemClicked()
|
||||
{
|
||||
if (data == null) return;
|
||||
|
||||
// 더블클릭 감지
|
||||
float currentTime = Time.unscaledTime;
|
||||
if (currentTime - _lastClickTime <= DoubleClickThreshold)
|
||||
{
|
||||
// 더블클릭 이벤트 발생
|
||||
treeList.OnItemDoubleClicked?.Invoke(data);
|
||||
_lastClickTime = 0f; // 연속 더블클릭 방지를 위해 초기화
|
||||
return; // 더블클릭 시 일반 클릭 처리 스킵
|
||||
}
|
||||
_lastClickTime = currentTime;
|
||||
|
||||
// 1. TreeList의 클릭 액션 이벤트 실행
|
||||
treeList.OnItemClickAction?.Invoke(data);
|
||||
|
||||
|
||||
@@ -351,5 +351,6 @@ namespace UVC.UI.List.Tree
|
||||
AddCloneAtChild,
|
||||
SwapChild,
|
||||
TailButtons,// 향후 버튼 관련 변경 추가 가능
|
||||
Delete, // 아이템 삭제 (Delete 키로 삭제 시)
|
||||
}
|
||||
}
|
||||
@@ -199,6 +199,7 @@ namespace UVC.UI.Menu
|
||||
/// <see cref="TopMenuView.OnMenuItemClicked"/> 이벤트가 발생했을 때 호출되는 핸들러입니다.
|
||||
/// 클릭된 메뉴 아이템(<paramref name="clickedItemData"/>)의 유효성을 검사하고,
|
||||
/// 연결된 <see cref="ICommand"/>를 실행합니다.
|
||||
/// IUndoableCommand인 경우 Undo/Redo 히스토리에 기록됩니다.
|
||||
/// </summary>
|
||||
/// <param name="clickedItemData">사용자가 클릭한 메뉴 아이템의 데이터입니다.</param>
|
||||
protected virtual void HandleMenuItemClicked(MenuItemData clickedItemData)
|
||||
@@ -223,9 +224,35 @@ namespace UVC.UI.Menu
|
||||
// 클릭된 메뉴 아이템 정보 로그 (디버깅 목적)
|
||||
ULog.Debug($"메뉴 아이템 클릭됨: {clickedItemData.ItemId} (표시 키: {clickedItemData.DisplayName})");
|
||||
|
||||
// 메뉴 아이템에 연결된 Command가 있다면 실행
|
||||
// Command가 null일 수 있으므로 null 조건부 연산자(?.) 사용
|
||||
clickedItemData.Command?.Execute(clickedItemData.CommandParameter);
|
||||
// 메뉴 아이템에 연결된 Command 실행
|
||||
ExecuteCommand(clickedItemData.Command, clickedItemData.CommandParameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Command를 실행합니다.
|
||||
/// IUndoableCommand인 경우 UndoRedoManager를 통해 실행하여 히스토리에 기록합니다.
|
||||
/// 일반 ICommand인 경우 직접 실행합니다.
|
||||
/// </summary>
|
||||
/// <param name="command">실행할 Command</param>
|
||||
/// <param name="parameter">Command 파라미터</param>
|
||||
protected virtual void ExecuteCommand(ICommand command, object parameter = null)
|
||||
{
|
||||
if (command == null) return;
|
||||
|
||||
// IUndoableCommand인 경우 UndoRedoManager를 통해 실행
|
||||
if (command is IUndoableCommand undoableCommand)
|
||||
{
|
||||
// UndoRedoManager가 존재하는지 확인 (Studio 씬에서만 사용 가능)
|
||||
var undoRedoManager = FindAnyObjectByType<UVC.Studio.Manager.UndoRedoManager>();
|
||||
if (undoRedoManager != null)
|
||||
{
|
||||
undoRedoManager.ExecuteCommand(undoableCommand, parameter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 일반 ICommand이거나 UndoRedoManager가 없는 경우 직접 실행
|
||||
command.Execute(parameter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UVC.Extention;
|
||||
using UVC.Log;
|
||||
using UVC.Studio.Manager;
|
||||
|
||||
namespace UVC.UI.Modal
|
||||
{
|
||||
@@ -119,6 +120,12 @@ namespace UVC.UI.Modal
|
||||
{
|
||||
//ULog.Debug($"[ModalView] {gameObject.name} OnOpen called.");
|
||||
|
||||
// 모달이 열리면 단축키 비활성화
|
||||
if (ShortcutManager.Instance != null)
|
||||
{
|
||||
ShortcutManager.Instance.GlobalEnabled = false;
|
||||
}
|
||||
|
||||
// ModalContent 레시피에 적힌 대로 UI 요소들을 설정해요.
|
||||
if (titleText != null && content != null)
|
||||
{
|
||||
@@ -177,6 +184,13 @@ namespace UVC.UI.Modal
|
||||
public virtual async UniTask OnClose(ModalContent content)
|
||||
{
|
||||
//ULog.Debug($"[ModalView] {gameObject.name} OnClose called.");
|
||||
|
||||
// 모달이 닫히면 단축키 다시 활성화
|
||||
if (ShortcutManager.Instance != null)
|
||||
{
|
||||
ShortcutManager.Instance.GlobalEnabled = true;
|
||||
}
|
||||
|
||||
// 예: 모달에서 사용했던 리소스를 해제하거나, UI 상태를 초기화하는 코드를 여기에 넣을 수 있어요.
|
||||
await UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace UVC.UI.Toolbar.Model
|
||||
/// 버튼 클릭 로직을 실행합니다.
|
||||
/// 이 메서드는 일반적으로 UI 시스템(예: Unity UI의 Button.onClick 이벤트)에 의해 호출되도록 설계됩니다.
|
||||
/// 버튼이 활성화(IsEnabled == true)되어 있고 ClickCommand가 할당되어 있다면, 해당 커맨드를 실행합니다.
|
||||
/// IUndoableCommand인 경우 UndoRedoManager를 통해 실행하여 Undo/Redo 히스토리에 기록됩니다.
|
||||
/// 파생 클래스에서 이 메서드를 재정의하여 특정 버튼 타입에 맞는 추가적인 클릭 동작을 구현할 수 있습니다.
|
||||
/// </summary>
|
||||
/// <param name="parameter">ClickCommand에 전달할 선택적 파라미터입니다.</param>
|
||||
@@ -199,7 +200,30 @@ namespace UVC.UI.Toolbar.Model
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
ClickCommand?.Execute(parameter); // 커맨드에 파라미터 전달
|
||||
if (ClickCommand != null)
|
||||
{
|
||||
// IUndoableCommand인 경우 UndoRedoManager를 통해 실행
|
||||
if (ClickCommand is IUndoableCommand undoableCommand)
|
||||
{
|
||||
// UndoRedoManager가 존재하는지 확인 (Studio 씬에서만 사용 가능)
|
||||
var undoRedoManager = UnityEngine.Object.FindAnyObjectByType<UVC.Studio.Manager.UndoRedoManager>();
|
||||
if (undoRedoManager != null)
|
||||
{
|
||||
undoRedoManager.ExecuteCommand(undoableCommand, parameter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// UndoRedoManager가 없으면 직접 실행
|
||||
ClickCommand.Execute(parameter);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 일반 ICommand는 직접 실행
|
||||
ClickCommand.Execute(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
OnClicked?.Invoke(); // 클릭 이벤트 발생
|
||||
}
|
||||
|
||||
|
||||
@@ -13,13 +13,13 @@ namespace UVC.UI.Window
|
||||
{
|
||||
/// <summary>
|
||||
/// 계층 데이터를 표시/검색/선택하는 창(View)입니다.
|
||||
///
|
||||
///
|
||||
/// 책임:
|
||||
/// - 메인 트리(`treeList`)와 검색 트리(`treeListSearch`)를 관리
|
||||
/// - 입력창으로 검색을 수행하고 결과를 검색 트리에 표시(청크 처리 + 로딩 애니메이션)
|
||||
/// - `TreeList.OnItemSelectionChanged`를 구독해 외부로 선택/해제 이벤트를 전달
|
||||
/// - 외부에서 호출 가능한 간단한 항목 추가/삭제 API 제공(실제 렌더링/상태는 `TreeList`가 담당)
|
||||
///
|
||||
///
|
||||
/// 사용 예:
|
||||
/// <example>
|
||||
/// <![CDATA[
|
||||
@@ -65,6 +65,16 @@ namespace UVC.UI.Window
|
||||
/// </summary>
|
||||
public System.Action<TreeListItemData, bool>? OnItemVisibilityChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 메인/검색 리스트에서 항목이 삭제될 때 발생합니다 (Delete 키).
|
||||
/// </summary>
|
||||
public System.Action<TreeListItemData>? OnItemDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// 메인/검색 리스트에서 항목이 더블클릭될 때 발생합니다.
|
||||
/// </summary>
|
||||
public System.Action<TreeListItemData>? OnItemDoubleClicked;
|
||||
|
||||
// 검색 목록에서 선택된 항목(클론된 데이터)
|
||||
protected TreeListItemData? selectedSearchItem;
|
||||
|
||||
@@ -97,6 +107,8 @@ namespace UVC.UI.Window
|
||||
{
|
||||
treeList.OnItemSelectionChanged += HandleMainSelectionChanged;
|
||||
treeList.OnItemVisibilityChanged += HandleMainVisibilityChanged;
|
||||
treeList.OnItemDataChanged += HandleMainDataChanged;
|
||||
treeList.OnItemDoubleClicked += HandleMainDoubleClicked;
|
||||
}
|
||||
|
||||
// 검색 리스트의 선택 변경을 감지 (선택 결과를 원본 트리에 반영하는 용도)
|
||||
@@ -104,6 +116,8 @@ namespace UVC.UI.Window
|
||||
{
|
||||
treeListSearch.OnItemSelectionChanged += OnSearchSelectionChanged;
|
||||
treeListSearch.OnItemVisibilityChanged += HandleMainVisibilityChanged;
|
||||
treeListSearch.OnItemDataChanged += HandleMainDataChanged;
|
||||
treeListSearch.OnItemDoubleClicked += HandleMainDoubleClicked;
|
||||
}
|
||||
|
||||
clearTextButton.onClick.AddListener(() =>
|
||||
@@ -362,6 +376,20 @@ namespace UVC.UI.Window
|
||||
OnItemVisibilityChanged?.Invoke(data, isVisible);
|
||||
}
|
||||
|
||||
protected void HandleMainDataChanged(ChangedType changedType, TreeListItemData data, int index)
|
||||
{
|
||||
// Delete 키로 삭제된 경우 외부 이벤트 발생
|
||||
if (changedType == ChangedType.Delete)
|
||||
{
|
||||
OnItemDeleted?.Invoke(data);
|
||||
}
|
||||
}
|
||||
|
||||
protected void HandleMainDoubleClicked(TreeListItemData data)
|
||||
{
|
||||
OnItemDoubleClicked?.Invoke(data);
|
||||
}
|
||||
|
||||
protected void OnInputFieldSubmit(string text)
|
||||
{
|
||||
// 검색어가 있으면 검색 결과 목록 표시
|
||||
@@ -502,17 +530,23 @@ namespace UVC.UI.Window
|
||||
{
|
||||
treeListSearch.OnItemSelectionChanged -= OnSearchSelectionChanged;
|
||||
treeListSearch.OnItemVisibilityChanged -= HandleMainVisibilityChanged;
|
||||
treeListSearch.OnItemDataChanged -= HandleMainDataChanged;
|
||||
treeListSearch.OnItemDoubleClicked -= HandleMainDoubleClicked;
|
||||
}
|
||||
|
||||
if (treeList != null)
|
||||
{
|
||||
treeList.OnItemSelectionChanged -= HandleMainSelectionChanged;
|
||||
treeList.OnItemVisibilityChanged -= HandleMainVisibilityChanged;
|
||||
treeList.OnItemDataChanged -= HandleMainDataChanged;
|
||||
treeList.OnItemDoubleClicked -= HandleMainDoubleClicked;
|
||||
}
|
||||
|
||||
// 4. 외부 이벤트 핸들러 정리
|
||||
OnItemSelected = null;
|
||||
OnItemDeselected = null;
|
||||
OnItemDeleted = null;
|
||||
OnItemDoubleClicked = null;
|
||||
|
||||
// 5. 참조 정리
|
||||
selectedSearchItem = null;
|
||||
|
||||
@@ -17,5 +17,12 @@ namespace UVC.UI.Window.PropertyWindow
|
||||
/// </summary>
|
||||
/// <param name="isReadOnly">읽기 전용 여부 (true: 비활성화, false: 활성화)</param>
|
||||
void SetReadOnly(bool isReadOnly);
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// Undo/Redo 시 PropertyValueChanged 이벤트 없이 값을 반영할 때 사용됩니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
void UpdateValue(object value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,5 +376,27 @@ namespace UVC.UI.Window.PropertyWindow
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Property Value Update
|
||||
|
||||
/// <summary>
|
||||
/// 특정 속성 아이템의 값을 UI에 반영합니다.
|
||||
/// Undo/Redo 시 PropertyValueChanged 이벤트 없이 값을 반영할 때 사용됩니다.
|
||||
/// </summary>
|
||||
/// <param name="propertyId">속성 아이템의 ID</param>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdatePropertyValue(string propertyId, object value)
|
||||
{
|
||||
if (_itemViews.TryGetValue(propertyId, out var itemView) && itemView != null)
|
||||
{
|
||||
var propertyUI = itemView.GetComponent<IPropertyUI>();
|
||||
if (propertyUI != null)
|
||||
{
|
||||
propertyUI.UpdateValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,6 +457,36 @@ namespace UVC.UI.Window.PropertyWindow
|
||||
PropertyValueChanged?.Invoke(this, new PropertyValueChangedEventArgs(propertyId, propertyType, oldValue, newValue));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 특정 ID를 가진 속성의 값을 설정합니다.
|
||||
/// 이 메서드는 Undo/Redo 시 값을 복원할 때 사용됩니다.
|
||||
/// PropertyValueChanged 이벤트를 발생시키지 않습니다.
|
||||
/// </summary>
|
||||
/// <param name="propertyId">값을 변경할 속성의 고유 ID</param>
|
||||
/// <param name="value">새로운 값</param>
|
||||
/// <returns>값이 성공적으로 설정되었는지 여부</returns>
|
||||
public bool SetPropertyValue(string propertyId, object? value)
|
||||
{
|
||||
if (!_itemIndex.TryGetValue(propertyId, out var propertyItem))
|
||||
{
|
||||
Debug.LogWarning($"[PropertyWindow] ID '{propertyId}'에 해당하는 속성을 찾을 수 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
propertyItem.SetValue(value);
|
||||
|
||||
// View에 값 반영 (UI 업데이트)
|
||||
if (_view != null)
|
||||
{
|
||||
_view.UpdatePropertyValue(propertyId, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Internal Helpers
|
||||
|
||||
@@ -111,6 +111,18 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (_valueToggle != null && value is bool boolValue)
|
||||
{
|
||||
_valueToggle.SetIsOnWithoutNotify(boolValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// 메모리 누수를 방지하기 위해 등록된 리스너를 제거합니다.
|
||||
|
||||
@@ -144,6 +144,19 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_colorPickerButton != null) _colorPickerButton.gameObject.SetActive(!isReadOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Color colorValue)
|
||||
{
|
||||
if (_colorPreviewImage != null) _colorPreviewImage.color = colorValue;
|
||||
if (_colorLabel != null) _colorLabel.SetTextWithoutNotify(ColorUtil.ToHex(colorValue, true, false));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -204,6 +204,23 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_colorPickerButton != null) _colorPickerButton.gameObject.SetActive(!isReadOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Tuple<string, string, Color?> colorStateValue)
|
||||
{
|
||||
if (_stateLabel != null) _stateLabel.SetTextWithoutNotify(colorStateValue.Item2);
|
||||
if (colorStateValue.Item3.HasValue)
|
||||
{
|
||||
if (_colorPreviewImage != null) _colorPreviewImage.color = colorStateValue.Item3.Value;
|
||||
if (_colorLabel != null) _colorLabel.SetTextWithoutNotify(ColorUtil.ToHex(colorStateValue.Item3.Value, true, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -128,6 +128,18 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is DateTime dateValue && _dateText != null)
|
||||
{
|
||||
_dateText.SetTextWithoutNotify(dateValue.ToString(DateFormat));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -171,6 +171,19 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Tuple<DateTime, DateTime> dateRange)
|
||||
{
|
||||
if (_startDateText != null) _startDateText.SetTextWithoutNotify(dateRange.Item1.ToString(DateFormat));
|
||||
if (_endDateText != null) _endDateText.SetTextWithoutNotify(dateRange.Item2.ToString(DateFormat));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -192,6 +192,20 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_miniteDropDown != null) _miniteDropDown.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is DateTime dateTimeValue)
|
||||
{
|
||||
if (_dateText != null) _dateText.SetTextWithoutNotify(dateTimeValue.ToString(DateFormat));
|
||||
if (_hourDropDown != null) _hourDropDown.SetValueWithoutNotify(dateTimeValue.Hour);
|
||||
if (_miniteDropDown != null) _miniteDropDown.SetValueWithoutNotify(dateTimeValue.Minute);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -303,6 +303,23 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_endMiniteDropDown != null) _endMiniteDropDown.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Tuple<DateTime, DateTime> dateTimeRange)
|
||||
{
|
||||
if (_startDateText != null) _startDateText.SetTextWithoutNotify(dateTimeRange.Item1.ToString(DateFormat));
|
||||
if (_endDateText != null) _endDateText.SetTextWithoutNotify(dateTimeRange.Item2.ToString(DateFormat));
|
||||
if (_startHourDropDown != null) _startHourDropDown.SetValueWithoutNotify(dateTimeRange.Item1.Hour);
|
||||
if (_startMiniteDropDown != null) _startMiniteDropDown.SetValueWithoutNotify(dateTimeRange.Item1.Minute);
|
||||
if (_endHourDropDown != null) _endHourDropDown.SetValueWithoutNotify(dateTimeRange.Item2.Hour);
|
||||
if (_endMiniteDropDown != null) _endMiniteDropDown.SetValueWithoutNotify(dateTimeRange.Item2.Minute);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -123,6 +123,22 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_dropdown != null) _dropdown.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (_dropdown != null && _enumValues != null && value != null)
|
||||
{
|
||||
int index = Array.IndexOf(_enumValues, value);
|
||||
if (index >= 0)
|
||||
{
|
||||
_dropdown.SetValueWithoutNotify(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -120,6 +120,22 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_dropdown != null) _dropdown.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (_dropdown != null && _propertyItem?.ItemsSource != null && value is string stringValue)
|
||||
{
|
||||
int index = _propertyItem.ItemsSource.IndexOf(stringValue);
|
||||
if (index >= 0)
|
||||
{
|
||||
_dropdown.SetValueWithoutNotify(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -215,6 +215,32 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value == null) return;
|
||||
|
||||
string textValue = value.ToString();
|
||||
if (_valueInput != null)
|
||||
{
|
||||
_valueInput.SetTextWithoutNotify(textValue);
|
||||
}
|
||||
if (_slider != null && _slider.gameObject.activeSelf)
|
||||
{
|
||||
if (value is int intValue)
|
||||
{
|
||||
_slider.SetValueWithoutNotify(intValue);
|
||||
}
|
||||
else if (value is float floatValue)
|
||||
{
|
||||
_slider.SetValueWithoutNotify(floatValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 오브젝트가 파괴될 때 리스너를 확실히 제거합니다.
|
||||
|
||||
@@ -195,6 +195,24 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_maxInputField != null) _maxInputField.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Tuple<int, int> intRange)
|
||||
{
|
||||
if (_minInputField != null) _minInputField.SetTextWithoutNotify(intRange.Item1.ToString(CultureInfo.InvariantCulture));
|
||||
if (_maxInputField != null) _maxInputField.SetTextWithoutNotify(intRange.Item2.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
else if (value is Tuple<float, float> floatRange)
|
||||
{
|
||||
if (_minInputField != null) _minInputField.SetTextWithoutNotify(floatRange.Item1.ToString(CultureInfo.InvariantCulture));
|
||||
if (_maxInputField != null) _maxInputField.SetTextWithoutNotify(floatRange.Item2.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -159,6 +159,21 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (_propertyItem?.ItemsSource == null || value is not string stringValue) return;
|
||||
|
||||
int index = _propertyItem.ItemsSource.IndexOf(stringValue);
|
||||
if (index >= 0 && index < _toggles.Count)
|
||||
{
|
||||
_toggles[index].SetIsOnWithoutNotify(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -104,6 +104,18 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (_valueInput != null && value != null)
|
||||
{
|
||||
_valueInput.SetTextWithoutNotify(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 오브젝트가 파괴될 때 리스너를 확실히 제거합니다.
|
||||
|
||||
@@ -183,6 +183,19 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_yInputField != null) _yInputField.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Vector2 vector2Value)
|
||||
{
|
||||
if (_xInputField != null) _xInputField.SetTextWithoutNotify(vector2Value.x.ToString(CultureInfo.InvariantCulture));
|
||||
if (_yInputField != null) _yInputField.SetTextWithoutNotify(vector2Value.y.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -216,6 +216,20 @@ namespace UVC.UI.Window.PropertyWindow.UI
|
||||
if (_zInputField != null) _zInputField.interactable = !isReadOnly;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public void UpdateValue(object value)
|
||||
{
|
||||
if (value is Vector3 vector3Value)
|
||||
{
|
||||
if (_xInputField != null) _xInputField.SetTextWithoutNotify(vector3Value.x.ToString(CultureInfo.InvariantCulture));
|
||||
if (_yInputField != null) _yInputField.SetTextWithoutNotify(vector3Value.y.ToString(CultureInfo.InvariantCulture));
|
||||
if (_zInputField != null) _zInputField.SetTextWithoutNotify(vector3Value.z.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 이 UI 오브젝트가 파괴될 때 Unity에 의해 호출됩니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -89,6 +89,26 @@ namespace UVC.UI.Window.PropertyWindow
|
||||
// 기본 구현 없음 - 파생 클래스에서 필요시 구현
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UI에 표시되는 값을 업데이트합니다.
|
||||
/// Undo/Redo 시 PropertyValueChanged 이벤트 없이 값을 반영할 때 사용됩니다.
|
||||
/// </summary>
|
||||
/// <param name="value">새로운 값</param>
|
||||
public virtual void UpdateValue(object value)
|
||||
{
|
||||
// 파생 클래스에서 구체적인 구현을 제공해야 합니다.
|
||||
ApplyValueToUI(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 파생 클래스에서 UI에 값을 적용합니다.
|
||||
/// </summary>
|
||||
/// <param name="value">적용할 값</param>
|
||||
protected virtual void ApplyValueToUI(object value)
|
||||
{
|
||||
// 기본 구현 없음 - 파생 클래스에서 필요시 구현
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Common UI Setup
|
||||
|
||||
Reference in New Issue
Block a user