추가 개발 전

This commit is contained in:
logonkhi
2025-11-12 16:48:34 +09:00
parent 8850f51193
commit 6920659ed9
13 changed files with 1359 additions and 21 deletions

View File

@@ -119,6 +119,329 @@ NavMeshSettings:
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &64787551
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 64787552}
- component: {fileID: 64787553}
m_Layer: 5
m_Name: Layout
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &64787552
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 64787551}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1069174847}
- {fileID: 2100428547}
- {fileID: 927013207}
m_Father: {fileID: 956875270}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -30}
m_SizeDelta: {x: 0, y: -60}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &64787553
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 64787551}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding:
m_Left: 0
m_Right: 0
m_Top: 0
m_Bottom: 0
m_ChildAlignment: 0
m_Spacing: 0
m_ChildForceExpandWidth: 0
m_ChildForceExpandHeight: 1
m_ChildControlWidth: 1
m_ChildControlHeight: 1
m_ChildScaleWidth: 0
m_ChildScaleHeight: 0
m_ReverseArrangement: 0
--- !u!1 &259817375
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 259817376}
- component: {fileID: 259817380}
- component: {fileID: 259817379}
- component: {fileID: 259817378}
- component: {fileID: 259817381}
m_Layer: 5
m_Name: dragButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &259817376
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 259817375}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 956875270}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 120, y: 42}
m_SizeDelta: {x: 36, y: 36}
m_Pivot: {x: 0.5, y: 0}
--- !u!114 &259817378
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 259817375}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 51a79c5175c14b74e8d98b30a07e387b, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &259817379
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 259817375}
m_CullTransparentMesh: 1
--- !u!114 &259817380
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 259817375}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4cdfc0facccb5164e87bd49a9a9be1e3, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &259817381
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 259817375}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 259817378}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &517076884
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 517076885}
- component: {fileID: 517076888}
- component: {fileID: 517076887}
- component: {fileID: 517076886}
m_Layer: 5
m_Name: expandButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &517076885
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 517076884}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2100428547}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -10, y: -20}
m_SizeDelta: {x: 36, y: 36}
m_Pivot: {x: 1, y: 1}
--- !u!114 &517076886
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 517076884}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 517076887}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &517076887
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 517076884}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 8a18b469b28bd6747a69823feb0f45bd, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &517076888
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 517076884}
m_CullTransparentMesh: 1
--- !u!1 &635492616 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 1913501843011813999, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
m_PrefabInstance: {fileID: 1069174846}
m_PrefabAsset: {fileID: 0}
--- !u!1 &701037396
GameObject:
m_ObjectHideFlags: 0
@@ -255,6 +578,116 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &927013206
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 927013207}
- component: {fileID: 927013209}
- component: {fileID: 927013208}
- component: {fileID: 927013210}
- component: {fileID: 927013211}
m_Layer: 5
m_Name: ModelDetailChartView
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &927013207
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927013206}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1370688471}
m_Father: {fileID: 64787552}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 1, y: 1}
--- !u!114 &927013208
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927013206}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.51370597, g: 0.6037058, b: 0.9811321, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &927013209
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927013206}
m_CullTransparentMesh: 1
--- !u!114 &927013210
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927013206}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1af5017c83fc5cf4d8fbd1d2a801a095, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &927013211
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 927013206}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: 1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &956875269
GameObject:
m_ObjectHideFlags: 0
@@ -264,6 +697,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 956875270}
- component: {fileID: 956875271}
m_Layer: 5
m_Name: BlockDetailModal
m_TagString: Untagged
@@ -285,7 +719,9 @@ RectTransform:
m_Children:
- {fileID: 1678519689}
- {fileID: 1996014045}
- {fileID: 1069174847}
- {fileID: 64787552}
- {fileID: 259817376}
- {fileID: 1981518846}
m_Father: {fileID: 1304768793}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -293,13 +729,33 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &956875271
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 956875269}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: daf98703dca342f458a0cf5df71adddb, type: 3}
m_Name:
m_EditorClassIdentifier:
closeButton: {fileID: 1996014046}
listView: {fileID: 1069174848}
modelView: {fileID: 2100428550}
chartView: {fileID: 927013210}
modelViewExpandButton: {fileID: 517076886}
chartViewExpandButton: {fileID: 1370688472}
dragButton: {fileID: 259817381}
showListButton: {fileID: 1981518847}
--- !u!1001 &1069174846
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 956875270}
m_TransformParent: {fileID: 64787552}
m_Modifications:
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_Pivot.x
@@ -315,7 +771,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchorMax.y
value: 1
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchorMin.x
@@ -327,11 +783,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_SizeDelta.x
value: 240
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_SizeDelta.y
value: -60
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_LocalPosition.x
@@ -367,7 +823,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchoredPosition.y
value: -60
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@@ -409,6 +865,22 @@ PrefabInstance:
propertyPath: m_Name
value: ShiHierarchyWindow
objectReference: {fileID: 0}
- target: {fileID: 2792550393869914720, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1069174848}
- target: {fileID: 2792550393869914720, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_MethodName
value: Close
objectReference: {fileID: 0}
- target: {fileID: 2792550393869914720, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_OnClick.m_PersistentCalls.m_Calls.Array.data[0].m_TargetAssemblyTypeName
value: SHI.modal.ModelDetailListView, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 3351413207641142582, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_SizeDelta.y
value: 2
objectReference: {fileID: 0}
- target: {fileID: 4429635802794036160, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_SizeDelta.x
value: 0
@@ -425,6 +897,10 @@ PrefabInstance:
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4629025237416871861, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4817867488375858252, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchorMax.x
value: 0
@@ -449,16 +925,54 @@ PrefabInstance:
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7450804729565234258, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 1913501843011813999, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
insertIndex: -1
addedObject: {fileID: 1069174851}
m_SourcePrefab: {fileID: 100100000, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
--- !u!224 &1069174847 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 1574318677252675885, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
m_PrefabInstance: {fileID: 1069174846}
m_PrefabAsset: {fileID: 0}
--- !u!114 &1069174848 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 8639307054254576253, guid: c6c35cdcefd487f4b910ceed76b50a8f, type: 3}
m_PrefabInstance: {fileID: 1069174846}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 635492616}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 59c744534c4342f4b9d032ed55beb194, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &1069174851
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 635492616}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: 240
m_PreferredHeight: -1
m_FlexibleWidth: 0
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &1304768789
GameObject:
m_ObjectHideFlags: 0
@@ -561,6 +1075,126 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 0}
--- !u!1 &1370688470
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1370688471}
- component: {fileID: 1370688474}
- component: {fileID: 1370688473}
- component: {fileID: 1370688472}
m_Layer: 5
m_Name: expandButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1370688471
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370688470}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 927013207}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 10, y: -20}
m_SizeDelta: {x: 36, y: 36}
m_Pivot: {x: 0, y: 1}
--- !u!114 &1370688472
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370688470}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1370688473}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1370688473
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370688470}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 8a18b469b28bd6747a69823feb0f45bd, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1370688474
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1370688470}
m_CullTransparentMesh: 1
--- !u!1 &1678519688
GameObject:
m_ObjectHideFlags: 0
@@ -973,6 +1607,126 @@ MonoBehaviour:
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 0
--- !u!1 &1981518845
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1981518846}
- component: {fileID: 1981518849}
- component: {fileID: 1981518848}
- component: {fileID: 1981518847}
m_Layer: 5
m_Name: showListButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1981518846
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1981518845}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 956875270}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 0, y: -76}
m_SizeDelta: {x: 40, y: 41}
m_Pivot: {x: 0, y: 1}
--- !u!114 &1981518847
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1981518845}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1981518848}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1981518848
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1981518845}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 7764a072d8c90494bb31837400339866, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1981518849
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1981518845}
m_CullTransparentMesh: 1
--- !u!1 &1996014044
GameObject:
m_ObjectHideFlags: 0
@@ -1093,6 +1847,116 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1996014044}
m_CullTransparentMesh: 1
--- !u!1 &2100428546
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2100428547}
- component: {fileID: 2100428549}
- component: {fileID: 2100428548}
- component: {fileID: 2100428550}
- component: {fileID: 2100428551}
m_Layer: 5
m_Name: ModelDetailView
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2100428547
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2100428546}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 517076885}
m_Father: {fileID: 64787552}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0, y: 1}
--- !u!114 &2100428548
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2100428546}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 0.8443396, b: 0.8443396, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &2100428549
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2100428546}
m_CullTransparentMesh: 1
--- !u!114 &2100428550
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2100428546}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 6f867baed0364ea4bb3ce7a26ce84bdf, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &2100428551
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2100428546}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: 1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0

View File

@@ -1,24 +1,25 @@
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using UVC.UI.Buttons;
using UVC.UI.Window;
namespace SHI.modal
{
public class BlockDetailModal: MonoBehaviour
public class BlockDetailModal : MonoBehaviour
{
[Header("References")]
[SerializeField]
private Button closeButton;
[SerializeField]
private HierarchyWindow hierarchyWindow;
private ModelDetailListView listView;
[SerializeField]
private ModelDetailView modelView;
[SerializeField]
private Transform chartView;
private ModelDetailChartView chartView;
[Header("UI Controls")]
[SerializeField]
private Button modelViewExpandButton;
@@ -29,11 +30,140 @@ namespace SHI.modal
private Button dragButton;
[SerializeField]
private ImageToggle showHierarchyButton;
private Button showListButton;
// cached layout elements for split control
private LayoutElement _modelLayout;
private LayoutElement _chartLayout;
private enum ExpandedSide { None, Model, Chart }
private ExpandedSide _expanded = ExpandedSide.None;
private RectTransform ModelRect => modelView != null ? modelView.GetComponent<RectTransform>() : null;
private RectTransform ChartRect => chartView != null ? chartView.GetComponent<RectTransform>() : null;
private HorizontalSplitDrag _splitter;
public void Start()
{
// Close
if (closeButton != null)
{
closeButton.onClick.AddListener(() => gameObject.SetActive(false));
}
// list show 버튼
if (showListButton != null && listView != null)
showListButton.onClick.AddListener(() =>
{
Debug.Log("BlockDetailModal: Show List View");
listView.gameObject.SetActive(true);
showListButton.gameObject.SetActive(false);
if (_splitter != null) _splitter.RefreshPosition();
});
showListButton.gameObject.SetActive(false);
// Selection wiring: list -> model/chart
if (listView != null)
{
listView.OnItemSelected += data =>
{
if (modelView != null) modelView.FocusItem(data);
if (chartView != null) chartView.SelectByItem(data.Name);
};
listView.OnClosed += () =>
{
if (showListButton != null) showListButton.gameObject.SetActive(true);
if (_splitter != null) _splitter.RefreshPosition();
};
}
// Selection wiring: model -> list/chart
if (modelView != null)
{
modelView.OnItemSelected += data =>
{
if (listView != null) listView.SelectItem(data.Name);
if (chartView != null) chartView.SelectByItem(data.Name);
};
}
// Chart -> list/model
if (chartView != null)
{
chartView.OnRowClicked += name =>
{
if (listView != null) listView.SelectItem(name);
if (modelView != null) modelView.FocusItemName(name);
};
}
// Expand buttons
if (modelViewExpandButton != null)
modelViewExpandButton.onClick.AddListener(ToggleExpandModel);
if (chartViewExpandButton != null)
chartViewExpandButton.onClick.AddListener(ToggleExpandChart);
// Drag splitter
SetupSplitControls();
}
private void SetupSplitControls()
{
var modelRect = ModelRect;
var chartRect = ChartRect;
if (modelRect == null || chartRect == null || dragButton == null) return;
_modelLayout = modelRect.GetComponent<LayoutElement>();
if (_modelLayout == null) _modelLayout = modelRect.gameObject.AddComponent<LayoutElement>();
_chartLayout = chartRect.GetComponent<LayoutElement>();
if (_chartLayout == null) _chartLayout = chartView.gameObject.AddComponent<LayoutElement>();
// initial split50/50
_modelLayout.flexibleWidth = 1f;
_chartLayout.flexibleWidth = 1f;
// attach drag handler
_splitter = dragButton.gameObject.GetComponent<HorizontalSplitDrag>();
if (_splitter == null) _splitter = dragButton.gameObject.AddComponent<HorizontalSplitDrag>();
var leftFixed = listView != null ? listView.GetComponent<RectTransform>() : null;
_splitter.Initialize(modelRect, chartRect, leftFixed);
//시간이 좀 필요 함
UniTask.DelayFrame(1).ContinueWith(() => _splitter.RefreshPosition());
}
private void ToggleExpandModel()
{
if (ModelRect == null || chartView == null) return;
if (_expanded == ExpandedSide.Model) { ResetSplit(); return; }
_expanded = ExpandedSide.Model;
ModelRect.gameObject.SetActive(true);
chartView.gameObject.SetActive(false);
if (_splitter != null) _splitter.gameObject.SetActive(false);
}
private void ToggleExpandChart()
{
if (ModelRect == null || chartView == null) return;
if (_expanded == ExpandedSide.Chart) { ResetSplit(); return; }
_expanded = ExpandedSide.Chart;
ModelRect.gameObject.SetActive(false);
chartView.gameObject.SetActive(true);
if (_splitter != null) _splitter.gameObject.SetActive(false);
}
private void ResetSplit()
{
_expanded = ExpandedSide.None;
if (ModelRect != null) ModelRect.gameObject.SetActive(true);
if (chartView != null) chartView.gameObject.SetActive(true);
if (_modelLayout != null) _modelLayout.flexibleWidth = 1f;
if (_chartLayout != null) _chartLayout.flexibleWidth = 1f;
if (_splitter != null)
{
_splitter.gameObject.SetActive(true);
_splitter.RefreshPosition();
}
}
}
}

View File

@@ -0,0 +1,128 @@
#nullable enable
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace SHI.modal
{
/// <summary>
/// 두 개의 RectTransform 가로 분할을 드래그 버튼으로 조절하는 간단한 스플리터.
/// 레이아웃 그룹(수평) + LayoutElement.flexibleWidth 기반으로 동작합니다.
/// </summary>
public class HorizontalSplitDrag : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
private RectTransform _left;
private RectTransform _right;
private LayoutElement _leftLayout;
private LayoutElement _rightLayout;
private RectTransform _parent;
private RectTransform _handleRect; // this splitter's rect
private float _parentWidth; // cached on begin drag
private float _handleY = 42; // keep original y
private RectTransform _leftFixedPanel; // e.g., ModelDetailListView root
private bool _lastLeftPanelActive;
private float _lastParentWidth;
public void Initialize(RectTransform left, RectTransform right, RectTransform? leftFixedPanel = null)
{
_left = left;
_right = right;
_leftFixedPanel = leftFixedPanel;
_parent = left != null ? left.parent as RectTransform : null;
_handleRect = transform as RectTransform;
_leftLayout = _left.GetComponent<LayoutElement>();
if (_leftLayout == null) _leftLayout = _left.gameObject.AddComponent<LayoutElement>();
_rightLayout = _right.GetComponent<LayoutElement>();
if (_rightLayout == null) _rightLayout = _right.gameObject.AddComponent<LayoutElement>();
_lastLeftPanelActive = _leftFixedPanel != null && _leftFixedPanel.gameObject.activeInHierarchy;
_lastParentWidth = _parent != null ? _parent.rect.width : 0f;
RefreshPosition();
}
public void OnBeginDrag(PointerEventData eventData)
{
if (_parent != null) _parentWidth = _parent.rect.width;
if (_handleRect != null) _handleY = _handleRect.anchoredPosition.y;
}
public void OnDrag(PointerEventData eventData)
{
if (_parent == null) return;
Vector2 local;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(_parent, eventData.position, eventData.pressEventCamera, out local))
return;
float width = _parent.rect.width;
if (width <= 0f) return;
// 계산 범위: 좌측 고정 패널(보이는 경우)의 폭만큼 좌측 경계를 오른쪽으로 이동
float leftOffset = 0f;
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
{
leftOffset = _leftFixedPanel.rect.width;
}
float minX = -width * 0.5f + leftOffset; // 사용 가능한 작업 영역의 좌측 경계
float maxX = width * 0.5f; // 우측 경계
// 현재 포인터 위치를 작업 영역 비율[0..1]로 변환 후 범위 제한
float t = Mathf.InverseLerp(minX, maxX, local.x);
t = Mathf.Clamp01(t);
// LayoutElement 비율 (양 끝 과도값 방지하여10%~90% 사이 유지)
float leftWeight = Mathf.Clamp(t, 0.1f, 0.9f);
float rightWeight = 1f - leftWeight;
_leftLayout.flexibleWidth = leftWeight;
_rightLayout.flexibleWidth = rightWeight;
// 스플리터 핸들도 같은 좌표계에서 이동
if (_handleRect != null)
{
float clampedX = Mathf.Lerp(minX, maxX, leftWeight);
_handleRect.anchoredPosition = new Vector2(clampedX, _handleY);
}
}
// 외부에서 강제로 현재 레이아웃 기준으로 핸들 위치를 동기화합니다.
public void RefreshPosition()
{
if (_parent == null || _handleRect == null || _leftLayout == null || _rightLayout == null)
return;
float width = _parent.rect.width;
if (width <= 0f) return;
float leftOffset = 0f;
if (_leftFixedPanel != null && _leftFixedPanel.gameObject.activeSelf)
leftOffset = _leftFixedPanel.rect.width;
float minX = -width * 0.5f + leftOffset;
float maxX = width * 0.5f;
float totalFlex = Mathf.Max(0.0001f, _leftLayout.flexibleWidth + _rightLayout.flexibleWidth);
float leftWeight = Mathf.Clamp01(_leftLayout.flexibleWidth / totalFlex);
leftWeight = Mathf.Clamp(leftWeight, 0.1f, 0.9f);
if (_handleRect != null)
{
_handleRect.anchoredPosition = new Vector2(Mathf.Lerp(minX, maxX, leftWeight), _handleY);
}
}
private void LateUpdate()
{
bool nowActive = _leftFixedPanel != null && _leftFixedPanel.gameObject.activeInHierarchy;
float nowWidth = _parent != null ? _parent.rect.width : 0f;
if (nowActive != _lastLeftPanelActive || !Mathf.Approximately(nowWidth, _lastParentWidth))
{
_lastLeftPanelActive = nowActive;
_lastParentWidth = nowWidth;
RefreshPosition();
}
}
public void OnEndDrag(PointerEventData eventData) { }
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4cdfc0facccb5164e87bd49a9a9be1e3

View File

@@ -0,0 +1,37 @@
#nullable enable
using System;
using UnityEngine;
namespace SHI.modal
{
/// <summary>
/// 차트 패널의 최소 동기화 컴포넌트.
/// 실제 UI Toolkit 기반 간트 컴포넌트가 준비되면 이 클래스를 연결하세요.
/// 현재는 항목 선택 신호만 송수신합니다.
/// </summary>
public class ModelDetailChartView : MonoBehaviour
{
/// <summary>
/// 차트의 행을 클릭했을 때 선택된 항목의 이름을 알립니다.
/// </summary>
public Action<string>? OnRowClicked;
/// <summary>
/// 외부(리스트/모델)에서 항목이 선택되었을 때 차트에서 해당 행을 강조합니다.
/// 실제 구현은 프로젝트의 차트 위젯에 맞게 교체하세요.
/// </summary>
public void SelectByItem(string name)
{
if (string.IsNullOrEmpty(name)) return;
Debug.Log($"ModelDetailChartView.SelectByItem: {name}");
// TODO: 차트에서 해당 행 스크롤/하이라이트
}
// 임시: UI 이벤트 바인딩에서 호출 가능한 샘플
public void SimulateRowClick(string name)
{
if (string.IsNullOrEmpty(name)) return;
OnRowClicked?.Invoke(name);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1af5017c83fc5cf4d8fbd1d2a801a095

View File

@@ -1,6 +1,7 @@
#nullable enable
using Cysharp.Threading.Tasks;
using DG.Tweening;
using System;
using System.Linq;
using System.Threading;
using TMPro;
@@ -52,16 +53,19 @@ namespace SHI.modal
/// <summary>
/// 메인/검색 리스트에서 항목이 선택될 때 발생합니다.
/// </summary>
public System.Action<TreeListItemData>? OnItemSelected;
public Action<TreeListItemData>? OnItemSelected;
/// <summary>
/// 메인/검색 리스트에서 항목이 선택 해제될 때 발생합니다.
/// </summary>
public System.Action<TreeListItemData>? OnItemDeselected;
public Action<TreeListItemData>? OnItemDeselected;
public Action? OnClosed;
// 검색 목록에서 선택된 항목(클론된 데이터)
protected TreeListItemData? selectedSearchItem;
// 검색 작업 상태
protected CancellationTokenSource? searchCts;
protected bool isSearching = false;
@@ -79,6 +83,7 @@ namespace SHI.modal
protected Tween? loadingRotationTween;
protected Tween? loadingFillTween;
protected void Awake()
{
loadingImage.gameObject.SetActive(false);
@@ -373,6 +378,12 @@ namespace SHI.modal
}
}
public void Close()
{
gameObject.SetActive(false);
OnClosed?.Invoke();
}
protected void OnDestroy()
{

View File

@@ -1,13 +1,49 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UVC.UI.List.Tree;
namespace SHI.modal
{
public class ModelDetailView: MonoBehaviour
{
/// <summary>
/// 모델 뷰 내에서 항목이 선택되었을 때 알림.
/// 외부에서 구독하여 리스트/차트를 동기화합니다.
/// </summary>
public Action<TreeListItemData>? OnItemSelected;
private TreeListItemData? _focused;
/// <summary>
/// 트리 아이템에 해당하는 모델 요소를 강조하거나 카메라를 이동합니다.
/// 실제 구현은 프로젝트 요구에 맞게 교체하세요.
/// </summary>
public void FocusItem(TreeListItemData data)
{
if (data == null) return;
_focused = data;
// TODO: 실제 GLTF/모델에서 data에 해당하는 노드를 찾아 강조/프레임 인
// 디버그 표시로 대체
Debug.Log($"ModelDetailView.FocusItem: {data.Name}");
}
/// <summary>
/// 주어진 이름에 해당하는 항목을 강조합니다.
/// </summary>
public void FocusItemName(string name)
{
if (string.IsNullOrEmpty(name)) return;
var data = new TreeListItemData(name);
FocusItem(data);
}
/// <summary>
/// 모델에서 사용자가 어떤 요소를 클릭했을 때 외부로 통지하려면 이 메서드를 호출하세요.
/// </summary>
public void RaiseSelected(TreeListItemData data)
{
OnItemSelected?.Invoke(data);
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9a7772b617c3413428e185c2e5e08f49
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

107
Assets/work.md Normal file
View File

@@ -0,0 +1,107 @@
### BlockDetailModal 통합 구현 작업지시서 (최종안)
**1. 목표**
`BlockDetailModal`의 3개 뷰(3D 모델, 계층 리스트, 간트 차트)를 통합하고, 모든 뷰가 상호 동기화되도록 완성한다.
**2. 핵심 데이터 계약 및 전략**
* **데이터 모델**: `SHI.modal.ModelDetailListItemData`를 핵심 데이터 단위로 사용한다.
* **고유 식별자**: 상속받은 `UVC.UI.List.Tree.TreeListItemData`**`public Guid Id`** 를 모든 동기화(선택, 포커스, 가시성)의 유일한 키로 사용한다. `Name` 기반의 기존 로직은 모두 `Id` 기반으로 변경한다.
* **데이터 정의**:
* `ScheduleSegment`: `Guid ItemId`, `DateTime Start`, `DateTime End`, `float Progress` (0-1), `string Type`
* `GanttChartData`: `List<ScheduleSegment> Segments`
* **라이브러리**: 3D 모델 로딩은 설치된 `glTFast (6.14.1)`를 사용한다.
**3. 샘플 데이터 및 모델 파일 생성**
* **샘플 glTF 모델**: `Assets/StreamingAssets/block.glb` 파일을 사용(또는 배치). 테스트 시 `LoadData` 호출에 `Path.Combine(Application.streamingAssetsPath, "block.glb")` 전달.
* **샘플 간트 데이터**: `Assets/StreamingAssets/sample_gantt_data.json` 파일을 생성한다. (폴더가 없으면 생성)
* **JSON 내용**: `GanttChartData` 구조에 맞는 샘플 JSON 데이터를 작성한다. `ItemId``ModelDetailView`에서 생성될 `ModelDetailListItemData``Id`와 일치해야 하므로, 초기 테스트를 위해 몇 개의 고정된 `Guid`를 사용한다.
```json
{
"Segments": [
{
"ItemId": "f81d4fae-7dec-11d0-a765-00a0c91e6bf6",
"Start": "2024-07-01T00:00:00Z",
"End": "2024-07-10T00:00:00Z",
"Progress": 0.5,
"Type": "Task"
},
{
"ItemId": "b2a8f0e0-0e3a-4b1a-9b0a-0e1b9b0f0e1b",
"Start": "2024-07-05T00:00:00Z",
"End": "2024-07-15T00:00:00Z",
"Progress": 0.2,
"Type": "Milestone"
}
]
}
```
**4. `BlockDetailModal.cs` 수정**
* **필드 추가**:
* `private CancellationTokenSource? _cts;`
* `private bool _isSelectionSuppressed;`
* **메서드 추가/수정**:
* `public async UniTask LoadData(string gltfPath, GanttChartData gantt, CancellationToken externalCt = default)`:
1. 기존 `_cts`가 있다면 취소하고 Dispose 한다. `_cts = CancellationTokenSource.CreateLinkedTokenSource(externalCt);`로 새로 생성한다.
2. (구현) 로딩 UI를 표시한다.
3. `modelView.LoadModelAsync(gltfPath, _cts.Token)`을 호출하여 `IEnumerable<ModelDetailListItemData>`를 받는다.
4. `listView.Populate(items)`로 리스트를 채운다.
5. `chartView.LoadData(gantt)`로 차트 데이터를 전달한다.
6. (구현) 로딩 UI를 숨긴다.
* `private void OnDisable()`: `_cts?.Cancel(); _cts?.Dispose();`를 호출하여 비활성화 시 모든 비동기 작업을 취소한다. `modelView`와 `chartView`의 리소스 정리(`Dispose`) 메서드를 호출한다.
* **이벤트 핸들러 수정 (`Start` 메서드 내)**:
* 모든 이벤트 연결을 `Id` 기반으로 변경하고, 재진입 방지 로직을 적용한다.
```csharp
// 예시: listView.OnItemSelected += ...
listView.OnItemSelected += data => {
if (_isSelectionSuppressed || data is not ModelDetailListItemData item) return;
HandleSelection(item.Id, "ListView");
};
// modelView, chartView도 동일하게 수정
```
* `private void HandleSelection(Guid itemId, string source)`:
```csharp
_isSelectionSuppressed = true;
if (source != "ListView") listView.SelectByItemId(itemId);
if (source != "ModelView") modelView.FocusItemById(itemId);
if (source != "ChartView") chartView.SelectByItemId(itemId);
// UniTask.Yield() 또는 DelayFrame(1)을 사용하여 한 프레임 뒤 false로 설정, 즉각적인 재진입 방지
UniTask.Yield(PlayerLoopTiming.PostLateUpdate, this.GetCancellationTokenOnDestroy()).ContinueWith(() => _isSelectionSuppressed = false);
```
**5. `ModelDetailView.cs` 구현**
* **메서드 추가**:
* `public async UniTask<IEnumerable<ModelDetailListItemData>> LoadModelAsync(string path, CancellationToken ct)`: `glTFast`를 사용하여 모델을 비동기 로드. 각 `GameObject`에 대해 `ModelDetailListItemData`를 생성하고 `Id`를 부여하여 `Dictionary<Guid, GameObject>`에 매핑 후, 데이터 목록을 반환한다.
* `public void FocusItemById(Guid id)`: `id`에 해당하는 `GameObject`의 `Bounds`를 계산하여 카메라를 부드럽게 이동/줌한다. 객체를 하이라이트한다.
* `public void SetVisibility(Guid id, bool isVisible)`: `id`에 해당하는 `GameObject`를 활성화/비활성화한다.
* `public void Dispose()`: 로드된 `GameObject`, 생성된 머티리얼 인스턴스 등 모든 리소스를 파괴한다.
* **구현 내용**:
* Raycast를 통한 객체 선택 로직을 구현하고, 선택 시 `OnItemSelected` 이벤트를 `Id`가 포함된 `ModelDetailListItemData`와 함께 발생시킨다.
* 객체 하이라이트를 위한 머티리얼 인스턴싱 및 캐시 관리 로직을 구현한다.
**6. `ModelDetailListView.cs` 수정/구현**
* **메서드 추가**:
* `public void Populate(IEnumerable<ModelDetailListItemData> items)`: 기존 항목을 모두 지우고 새 데이터로 트리를 구성한다.
* `public void SelectByItemId(Guid id)`: `id`에 해당하는 아이템을 찾아 선택 상태로 만든다.
* **가시성 처리**:
* `Populate` 시, 각 `ModelDetailListItemData`의 `OnClickVisibleAction`에 `(data, isVisible) => { if(data is ModelDetailListItemData item) OnVisibilityChanged?.Invoke(item.Id, isVisible); }` 와 같은 람다를 할당한다.
* `public event Action<Guid, bool> OnVisibilityChanged;` 이벤트를 추가하고, `BlockDetailModal`에서 이 이벤트를 구독하여 `modelView.SetVisibility`를 호출하도록 연결한다.
**7. `ModelDetailChartView.cs` 구현**
* **메서드 추가**:
* `public void LoadData(GanttChartData data)`: 차트 데이터를 받아 렌더링한다.
* `public void SelectByItemId(Guid id)`: `id`에 해당하는 행을 찾아 하이라이트하고, 해당 위치로 스크롤한다.
* `public event Action<Guid> OnRowClicked;` (`string`에서 `Guid`로 변경)
* `public void Dispose()`: UI Toolkit으로 생성된 동적 요소들을 정리한다.
* **구현 내용**:
* UI Toolkit의 `ListView`를 사용하여 행 가상화를 구현한다.
* 행 클릭 시 `OnRowClicked` 이벤트를 `ItemId`와 함께 발생시킨다.
**8. 실행 우선순위**
1. **데이터 계약**: `ScheduleSegment`/`GanttChartData` 클래스 생성 및 샘플 JSON/GLB 파일 작성.
2. **ID 기반 리팩토링**: `BlockDetailModal` 및 각 뷰의 이벤트와 메서드 시그니처를 `string name`에서 `Guid Id`로 모두 변경.
3. **뷰 구현**: `ModelDetailView`의 모델 로딩, `ModelDetailListView`의 `Populate`, `ModelDetailChartView`의 `LoadData`를 순서대로 구현.
4. **동기화 로직**: `BlockDetailModal`에 재진입 방지 로직(`_isSelectionSuppressed`)을 포함한 `HandleSelection` 구현.
5. **세부 기능**: 하이라이트, 카메라 포커싱, 가시성 토글, 차트 스크롤링 순으로 구현.
6. **생명주기**: `OnDisable`과 각 뷰의 `Dispose` 메서드에 리소스 정리 로직을 철저히 구현.
7. **테스트**: 중복 이름 아이템 선택, 빠른 모달 닫기 등 엣지 케이스를 포함하여 테스트.