- BackgroundSceneLoaderWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField) - PropBrowserWindow: OnGUI → CreateGUI (Toolbar + ToolbarSearchField) - StreamingleCommon.uss: 브라우저 공통 스타일 추가 (그리드/리스트/뷰토글/액션바/상태바) - excludeFromWeb 상태 새로고침 시 보존 수정 - 삭제된 배경 리소스 정리 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
168 lines
6.8 KiB
C#
168 lines
6.8 KiB
C#
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.UIElements;
|
|
|
|
namespace KindRetargeting
|
|
{
|
|
[CustomEditor(typeof(PropLocationController))]
|
|
public class PropLocationControllerEditor : BaseRetargetingEditor
|
|
{
|
|
private const string CommonUssPath = "Assets/Scripts/Streamingle/StreamingleControl/Editor/UXML/StreamingleCommon.uss";
|
|
|
|
private VisualElement offsetContainer;
|
|
private VisualElement propListContainer;
|
|
private PropLocationController controller;
|
|
|
|
public override VisualElement CreateInspectorGUI()
|
|
{
|
|
controller = target as PropLocationController;
|
|
if (controller == null) return new VisualElement();
|
|
var root = new VisualElement();
|
|
|
|
var commonUss = AssetDatabase.LoadAssetAtPath<StyleSheet>(CommonUssPath);
|
|
if (commonUss != null) root.styleSheets.Add(commonUss);
|
|
|
|
// 기본 프로퍼티
|
|
var iterator = serializedObject.GetIterator();
|
|
iterator.NextVisible(true); // skip m_Script
|
|
while (iterator.NextVisible(false))
|
|
{
|
|
var field = new PropertyField(iterator.Copy());
|
|
root.Add(field);
|
|
}
|
|
|
|
// 오프셋 조정 섹션
|
|
root.Add(new Label("오프셋 조정") { style = { unityFontStyleAndWeight = FontStyle.Bold, marginTop = 10 } });
|
|
offsetContainer = new VisualElement();
|
|
root.Add(offsetContainer);
|
|
|
|
// 부착된 프랍 목록 섹션
|
|
root.Add(new Label("부착된 프랍 목록") { style = { unityFontStyleAndWeight = FontStyle.Bold, marginTop = 10 } });
|
|
propListContainer = new VisualElement();
|
|
root.Add(propListContainer);
|
|
|
|
// 프랍 위치 이동 버튼
|
|
root.Add(new Label("프랍 위치 이동") { style = { unityFontStyleAndWeight = FontStyle.Bold, marginTop = 10 } });
|
|
var btnRow = new VisualElement { style = { flexDirection = FlexDirection.Row, marginTop = 4 } };
|
|
|
|
var headBtn = new Button(() => controller.MoveToHead()) { text = "머리로 이동" };
|
|
headBtn.style.flexGrow = 1; headBtn.style.height = 30; headBtn.style.marginRight = 2;
|
|
btnRow.Add(headBtn);
|
|
|
|
var leftBtn = new Button(() => controller.MoveToLeftHand()) { text = "왼손으로 이동" };
|
|
leftBtn.style.flexGrow = 1; leftBtn.style.height = 30; leftBtn.style.marginRight = 2;
|
|
btnRow.Add(leftBtn);
|
|
|
|
var rightBtn = new Button(() => controller.MoveToRightHand()) { text = "오른손으로 이동" };
|
|
rightBtn.style.flexGrow = 1; rightBtn.style.height = 30;
|
|
btnRow.Add(rightBtn);
|
|
|
|
root.Add(btnRow);
|
|
|
|
var detachBtn = new Button(() =>
|
|
{
|
|
if (Selection.activeGameObject != null)
|
|
Undo.RecordObject(Selection.activeGameObject.transform, "Detach Prop");
|
|
controller.DetachProp();
|
|
}) { text = "프랍 해제" };
|
|
detachBtn.style.height = 30;
|
|
detachBtn.style.marginTop = 4;
|
|
root.Add(detachBtn);
|
|
|
|
// 주기적으로 동적 UI 갱신
|
|
root.schedule.Execute(() => RebuildDynamicUI()).Every(500);
|
|
RebuildDynamicUI();
|
|
|
|
return root;
|
|
}
|
|
|
|
private void RebuildDynamicUI()
|
|
{
|
|
if (controller == null) return;
|
|
RebuildOffsets();
|
|
RebuildPropLists();
|
|
}
|
|
|
|
private void RebuildOffsets()
|
|
{
|
|
if (offsetContainer == null) return;
|
|
offsetContainer.Clear();
|
|
|
|
BuildOffsetSection(offsetContainer, "왼손 오프셋", controller.GetLeftHandOffset());
|
|
BuildOffsetSection(offsetContainer, "오른손 오프셋", controller.GetRightHandOffset());
|
|
BuildOffsetSection(offsetContainer, "머리 오프셋", controller.GetHeadOffset());
|
|
}
|
|
|
|
private void BuildOffsetSection(VisualElement parent, string label, Transform offset)
|
|
{
|
|
if (offset == null) return;
|
|
|
|
var foldout = new Foldout { text = label, value = true };
|
|
|
|
var posField = new Vector3Field("위치") { value = offset.localPosition };
|
|
posField.RegisterValueChangedCallback(evt =>
|
|
{
|
|
Undo.RecordObject(offset, $"Update {label}");
|
|
offset.localPosition = evt.newValue;
|
|
EditorUtility.SetDirty(offset);
|
|
});
|
|
foldout.Add(posField);
|
|
|
|
var rotField = new Vector3Field("회전") { value = offset.localRotation.eulerAngles };
|
|
rotField.RegisterValueChangedCallback(evt =>
|
|
{
|
|
Undo.RecordObject(offset, $"Update {label}");
|
|
offset.localRotation = Quaternion.Euler(evt.newValue);
|
|
EditorUtility.SetDirty(offset);
|
|
});
|
|
foldout.Add(rotField);
|
|
|
|
parent.Add(foldout);
|
|
}
|
|
|
|
private void RebuildPropLists()
|
|
{
|
|
if (propListContainer == null) return;
|
|
propListContainer.Clear();
|
|
|
|
BuildPropListSection(propListContainer, "머리 프랍", controller.GetHeadProps());
|
|
BuildPropListSection(propListContainer, "왼손 프랍", controller.GetLeftHandProps());
|
|
BuildPropListSection(propListContainer, "오른손 프랍", controller.GetRightHandProps());
|
|
}
|
|
|
|
private void BuildPropListSection(VisualElement parent, string title, GameObject[] propList)
|
|
{
|
|
var box = new VisualElement();
|
|
box.style.backgroundColor = new Color(0, 0, 0, 0.1f);
|
|
box.style.borderTopLeftRadius = box.style.borderTopRightRadius =
|
|
box.style.borderBottomLeftRadius = box.style.borderBottomRightRadius = 4;
|
|
box.style.paddingTop = box.style.paddingBottom =
|
|
box.style.paddingLeft = box.style.paddingRight = 4;
|
|
box.style.marginBottom = 4;
|
|
|
|
box.Add(new Label(title) { style = { unityFontStyleAndWeight = FontStyle.Bold } });
|
|
|
|
if (propList.Length > 0)
|
|
{
|
|
foreach (var prop in propList)
|
|
{
|
|
if (prop == null) continue;
|
|
var row = new VisualElement { style = { flexDirection = FlexDirection.Row, alignItems = Align.Center, marginTop = 2 } };
|
|
row.Add(new Label(prop.name) { style = { flexGrow = 1 } });
|
|
var selectBtn = new Button(() => Selection.activeGameObject = prop) { text = "선택" };
|
|
selectBtn.style.width = 60;
|
|
row.Add(selectBtn);
|
|
box.Add(row);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
box.Add(new Label("부착된 프랍 없음") { style = { color = new Color(0.6f, 0.6f, 0.6f) } });
|
|
}
|
|
|
|
parent.Add(box);
|
|
}
|
|
}
|
|
}
|