diff --git a/Assets/Scenes/Sample/ShiPopupSample.unity b/Assets/Scenes/Sample/ShiPopupSample.unity index ce6db258..38e3ea6b 100644 --- a/Assets/Scenes/Sample/ShiPopupSample.unity +++ b/Assets/Scenes/Sample/ShiPopupSample.unity @@ -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 diff --git a/Assets/Scripts/SHI/modal/BlockDetailModal.cs b/Assets/Scripts/SHI/modal/BlockDetailModal.cs index 2dc724a0..511e4719 100644 --- a/Assets/Scripts/SHI/modal/BlockDetailModal.cs +++ b/Assets/Scripts/SHI/modal/BlockDetailModal.cs @@ -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() : null; + private RectTransform ChartRect => chartView != null ? chartView.GetComponent() : 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(); + if (_modelLayout == null) _modelLayout = modelRect.gameObject.AddComponent(); + + _chartLayout = chartRect.GetComponent(); + if (_chartLayout == null) _chartLayout = chartView.gameObject.AddComponent(); + + // initial split50/50 + _modelLayout.flexibleWidth = 1f; + _chartLayout.flexibleWidth = 1f; + + // attach drag handler + _splitter = dragButton.gameObject.GetComponent(); + if (_splitter == null) _splitter = dragButton.gameObject.AddComponent(); + var leftFixed = listView != null ? listView.GetComponent() : 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(); + } } } } diff --git a/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs b/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs new file mode 100644 index 00000000..26099fc9 --- /dev/null +++ b/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs @@ -0,0 +1,128 @@ +#nullable enable +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace SHI.modal +{ + /// + /// 두 개의 RectTransform 가로 분할을 드래그 버튼으로 조절하는 간단한 스플리터. + /// 레이아웃 그룹(수평) + LayoutElement.flexibleWidth 기반으로 동작합니다. + /// + 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(); + if (_leftLayout == null) _leftLayout = _left.gameObject.AddComponent(); + _rightLayout = _right.GetComponent(); + if (_rightLayout == null) _rightLayout = _right.gameObject.AddComponent(); + + _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) { } + } +} diff --git a/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs.meta b/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs.meta new file mode 100644 index 00000000..bc048901 --- /dev/null +++ b/Assets/Scripts/SHI/modal/HorizontalSplitDrag.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4cdfc0facccb5164e87bd49a9a9be1e3 \ No newline at end of file diff --git a/Assets/Scripts/SHI/modal/ModelDetailChartView.cs b/Assets/Scripts/SHI/modal/ModelDetailChartView.cs new file mode 100644 index 00000000..ddb42c8b --- /dev/null +++ b/Assets/Scripts/SHI/modal/ModelDetailChartView.cs @@ -0,0 +1,37 @@ +#nullable enable +using System; +using UnityEngine; + +namespace SHI.modal +{ + /// + /// 차트 패널의 최소 동기화 컴포넌트. + /// 실제 UI Toolkit 기반 간트 컴포넌트가 준비되면 이 클래스를 연결하세요. + /// 현재는 항목 선택 신호만 송수신합니다. + /// + public class ModelDetailChartView : MonoBehaviour + { + /// + /// 차트의 행을 클릭했을 때 선택된 항목의 이름을 알립니다. + /// + public Action? OnRowClicked; + + /// + /// 외부(리스트/모델)에서 항목이 선택되었을 때 차트에서 해당 행을 강조합니다. + /// 실제 구현은 프로젝트의 차트 위젯에 맞게 교체하세요. + /// + 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); + } + } +} diff --git a/Assets/Scripts/SHI/modal/ModelDetailChartView.cs.meta b/Assets/Scripts/SHI/modal/ModelDetailChartView.cs.meta new file mode 100644 index 00000000..918571d3 --- /dev/null +++ b/Assets/Scripts/SHI/modal/ModelDetailChartView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1af5017c83fc5cf4d8fbd1d2a801a095 \ No newline at end of file diff --git a/Assets/Scripts/SHI/modal/ModelDetailListView.cs b/Assets/Scripts/SHI/modal/ModelDetailListView.cs index 0fcbfdf5..27a90e2a 100644 --- a/Assets/Scripts/SHI/modal/ModelDetailListView.cs +++ b/Assets/Scripts/SHI/modal/ModelDetailListView.cs @@ -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 /// /// 메인/검색 리스트에서 항목이 선택될 때 발생합니다. /// - public System.Action? OnItemSelected; + public Action? OnItemSelected; /// /// 메인/검색 리스트에서 항목이 선택 해제될 때 발생합니다. /// - public System.Action? OnItemDeselected; + public Action? 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() { diff --git a/Assets/Scripts/SHI/modal/ModelDetailView.cs b/Assets/Scripts/SHI/modal/ModelDetailView.cs index 4a58ec9e..26ba371c 100644 --- a/Assets/Scripts/SHI/modal/ModelDetailView.cs +++ b/Assets/Scripts/SHI/modal/ModelDetailView.cs @@ -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 { + /// + /// 모델 뷰 내에서 항목이 선택되었을 때 알림. + /// 외부에서 구독하여 리스트/차트를 동기화합니다. + /// + public Action? OnItemSelected; + + private TreeListItemData? _focused; + + /// + /// 트리 아이템에 해당하는 모델 요소를 강조하거나 카메라를 이동합니다. + /// 실제 구현은 프로젝트 요구에 맞게 교체하세요. + /// + public void FocusItem(TreeListItemData data) + { + if (data == null) return; + _focused = data; + // TODO: 실제 GLTF/모델에서 data에 해당하는 노드를 찾아 강조/프레임 인 + // 디버그 표시로 대체 + Debug.Log($"ModelDetailView.FocusItem: {data.Name}"); + } + + /// + /// 주어진 이름에 해당하는 항목을 강조합니다. + /// + public void FocusItemName(string name) + { + if (string.IsNullOrEmpty(name)) return; + var data = new TreeListItemData(name); + FocusItem(data); + } + + /// + /// 모델에서 사용자가 어떤 요소를 클릭했을 때 외부로 통지하려면 이 메서드를 호출하세요. + /// + public void RaiseSelected(TreeListItemData data) + { + OnItemSelected?.Invoke(data); + } } } diff --git a/Assets/StreamingAssets/block.glb b/Assets/StreamingAssets/block.glb new file mode 100644 index 00000000..9c5723a0 Binary files /dev/null and b/Assets/StreamingAssets/block.glb differ diff --git a/Assets/StreamingAssets/block.glb.meta b/Assets/StreamingAssets/block.glb.meta new file mode 100644 index 00000000..5d563d68 --- /dev/null +++ b/Assets/StreamingAssets/block.glb.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9a7772b617c3413428e185c2e5e08f49 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/work.md b/Assets/work.md new file mode 100644 index 00000000..642899d6 --- /dev/null +++ b/Assets/work.md @@ -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 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`를 받는다. + 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> LoadModelAsync(string path, CancellationToken ct)`: `glTFast`를 사용하여 모델을 비동기 로드. 각 `GameObject`에 대해 `ModelDetailListItemData`를 생성하고 `Id`를 부여하여 `Dictionary`에 매핑 후, 데이터 목록을 반환한다. + * `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 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 OnVisibilityChanged;` 이벤트를 추가하고, `BlockDetailModal`에서 이 이벤트를 구독하여 `modelView.SetVisibility`를 호출하도록 연결한다. + +**7. `ModelDetailChartView.cs` 구현** +* **메서드 추가**: + * `public void LoadData(GanttChartData data)`: 차트 데이터를 받아 렌더링한다. + * `public void SelectByItemId(Guid id)`: `id`에 해당하는 행을 찾아 하이라이트하고, 해당 위치로 스크롤한다. + * `public event Action 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. **테스트**: 중복 이름 아이템 선택, 빠른 모달 닫기 등 엣지 케이스를 포함하여 테스트. diff --git a/Packages/manifest.json b/Packages/manifest.json index 891bd8b4..9363c56e 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -4,6 +4,7 @@ "com.github-glitchenzo.nugetforunity": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity", "com.unity.2d.sprite": "1.0.0", "com.unity.ai.navigation": "2.0.5", + "com.unity.cloud.gltfast": "6.14.1", "com.unity.collab-proxy": "2.8.2", "com.unity.ide.rider": "3.0.31", "com.unity.ide.visualstudio": "2.0.23", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 11ecf4ab..71bbd69e 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -30,7 +30,7 @@ "url": "https://packages.unity.com" }, "com.unity.burst": { - "version": "1.8.18", + "version": "1.8.24", "depth": 1, "source": "registry", "dependencies": { @@ -39,6 +39,19 @@ }, "url": "https://packages.unity.com" }, + "com.unity.cloud.gltfast": { + "version": "6.14.1", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.24", + "com.unity.collections": "1.2.4", + "com.unity.mathematics": "1.2.6", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.collab-proxy": { "version": "2.8.2", "depth": 0,