user 4a49ecd772 Refactor: 배경/프랍 브라우저 IMGUI→UI Toolkit 전환 + USS 리디자인
- BackgroundSceneLoaderWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField)
- PropBrowserWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField)
- StreamingleCommon.uss: 브라우저 공통 스타일 추가 (그리드/리스트/뷰토글/액션바/상태바)
- excludeFromWeb 상태 새로고침 시 보존 수정
- 삭제된 배경 리소스 정리

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 01:55:48 +09:00

214 lines
6.9 KiB
C#

using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
[CustomEditor(typeof(ItemController))]
public class ItemControllerEditor : Editor
{
private const string UxmlPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/ItemControllerEditor.uxml";
private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss";
private VisualElement itemsContainer;
private Label itemsTitleLabel;
private ItemController controller;
public override VisualElement CreateInspectorGUI()
{
controller = (ItemController)target;
var root = new VisualElement();
var commonUss = AssetDatabase.LoadAssetAtPath<StyleSheet>(CommonUssPath);
if (commonUss != null) root.styleSheets.Add(commonUss);
var uxml = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(UxmlPath);
if (uxml != null) uxml.CloneTree(root);
BuildItemGroupsSection(root);
root.schedule.Execute(UpdatePlayModeState).Every(200);
Undo.undoRedoPerformed += OnUndoRedo;
root.RegisterCallback<DetachFromPanelEvent>(_ => Undo.undoRedoPerformed -= OnUndoRedo);
return root;
}
private void OnUndoRedo()
{
if (controller == null) return;
serializedObject.Update();
RebuildItemList();
}
#region Item Groups List
private void BuildItemGroupsSection(VisualElement root)
{
var section = root.Q("itemGroupsSection");
if (section == null) return;
var header = new VisualElement();
header.AddToClassList("list-header");
itemsTitleLabel = new Label($"아이템 그룹 ({controller.itemGroups.Count})");
itemsTitleLabel.AddToClassList("list-title");
header.Add(itemsTitleLabel);
var addBtn = new Button(AddItemGroup) { text = "+ 그룹 추가" };
addBtn.AddToClassList("list-add-btn");
header.Add(addBtn);
section.Add(header);
itemsContainer = new VisualElement();
section.Add(itemsContainer);
RebuildItemList();
}
private void RebuildItemList()
{
if (itemsContainer == null || controller == null) return;
itemsContainer.Clear();
if (itemsTitleLabel != null)
itemsTitleLabel.text = $"아이템 그룹 ({controller.itemGroups.Count})";
if (controller.itemGroups.Count == 0)
{
var empty = new Label("아이템 그룹이 없습니다. '+ 그룹 추가' 버튼을 눌러 추가하세요.");
empty.AddToClassList("list-empty");
itemsContainer.Add(empty);
return;
}
for (int i = 0; i < controller.itemGroups.Count; i++)
{
itemsContainer.Add(CreateItemGroupElement(i));
}
}
private VisualElement CreateItemGroupElement(int index)
{
var group = controller.itemGroups[index];
bool isActive = Application.isPlaying && group.IsActive();
var item = new VisualElement();
item.AddToClassList("list-item");
if (isActive) item.AddToClassList("list-item--active");
// Header row
var headerRow = new VisualElement();
headerRow.AddToClassList("list-item-header");
var indexLabel = new Label($"{index + 1}");
indexLabel.AddToClassList("list-index");
headerRow.Add(indexLabel);
var nameField = new TextField();
nameField.value = group.groupName;
nameField.AddToClassList("list-name-field");
int idx = index;
nameField.RegisterValueChangedCallback(evt =>
{
Undo.RecordObject(target, "Rename Item Group");
controller.itemGroups[idx].groupName = evt.newValue;
EditorUtility.SetDirty(target);
});
headerRow.Add(nameField);
if (isActive)
{
var activeLabel = new Label("[Active]");
activeLabel.AddToClassList("list-active-label");
headerRow.Add(activeLabel);
}
// Reorder buttons
var upBtn = new Button(() => SwapItems(idx, idx - 1)) { text = "\u25B2" };
upBtn.AddToClassList("list-reorder-btn");
upBtn.SetEnabled(index > 0);
headerRow.Add(upBtn);
var downBtn = new Button(() => SwapItems(idx, idx + 1)) { text = "\u25BC" };
downBtn.AddToClassList("list-reorder-btn");
downBtn.SetEnabled(index < controller.itemGroups.Count - 1);
headerRow.Add(downBtn);
var deleteBtn = new Button(() => DeleteItem(idx)) { text = "X" };
deleteBtn.AddToClassList("list-delete-btn");
headerRow.Add(deleteBtn);
item.Add(headerRow);
// Fields
var fields = new VisualElement();
fields.AddToClassList("list-fields");
var listProp = serializedObject.FindProperty("itemGroups");
var elementProp = listProp.GetArrayElementAtIndex(index);
var objectsField = new PropertyField(elementProp.FindPropertyRelative("itemObjects"), "오브젝트");
fields.Add(objectsField);
item.Add(fields);
return item;
}
private void AddItemGroup()
{
Undo.RecordObject(target, "Add Item Group");
controller.itemGroups.Add(new ItemController.ItemGroup("새 아이템 그룹"));
EditorUtility.SetDirty(target);
serializedObject.Update();
RebuildItemList();
}
private void DeleteItem(int index)
{
var group = controller.itemGroups[index];
if (EditorUtility.DisplayDialog("그룹 삭제",
$"그룹 '{group.groupName}'을(를) 삭제하시겠습니까?", "삭제", "취소"))
{
Undo.RecordObject(target, "Delete Item Group");
controller.itemGroups.RemoveAt(index);
EditorUtility.SetDirty(target);
serializedObject.Update();
RebuildItemList();
}
}
private void SwapItems(int a, int b)
{
Undo.RecordObject(target, "Reorder Item Groups");
(controller.itemGroups[a], controller.itemGroups[b]) = (controller.itemGroups[b], controller.itemGroups[a]);
EditorUtility.SetDirty(target);
serializedObject.Update();
RebuildItemList();
}
#endregion
#region Play Mode State
private void UpdatePlayModeState()
{
if (itemsContainer == null || controller == null) return;
if (!Application.isPlaying) return;
for (int i = 0; i < itemsContainer.childCount && i < controller.itemGroups.Count; i++)
{
var item = itemsContainer[i];
bool isActive = controller.itemGroups[i].IsActive();
if (isActive && !item.ClassListContains("list-item--active"))
item.AddToClassList("list-item--active");
else if (!isActive && item.ClassListContains("list-item--active"))
item.RemoveFromClassList("list-item--active");
}
}
#endregion
}