From 63b71216cb5caecf7eb0edcff6bab83333ccd0bd Mon Sep 17 00:00:00 2001 From: logonkhi Date: Mon, 16 Jun 2025 19:30:01 +0900 Subject: [PATCH] =?UTF-8?q?toolbar=20=EA=B0=9C=EB=B0=9C=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Resources/Prefabs/UI/Toolbar.meta | 8 + .../Prefabs/UI/Toolbar/Toolbar.prefab | 138 +++++++ .../Prefabs/UI/Toolbar/Toolbar.prefab.meta | 7 + .../UI/Toolbar/ToolbarExpandableButton.prefab | 272 ++++++++++++++ .../ToolbarExpandableButton.prefab.meta | 7 + .../UI/Toolbar/ToolbarRadioButton.prefab | 331 +++++++++++++++++ .../UI/Toolbar/ToolbarRadioButton.prefab.meta | 7 + .../UI/Toolbar/ToolbarSeparator.prefab | 77 ++++ .../UI/Toolbar/ToolbarSeparator.prefab.meta | 7 + .../UI/Toolbar/ToolbarStandardButton.prefab | 272 ++++++++++++++ .../Toolbar/ToolbarStandardButton.prefab.meta | 7 + .../UI/Toolbar/ToolbarSubMenuPanel.prefab | 104 ++++++ .../Toolbar/ToolbarSubMenuPanel.prefab.meta | 7 + .../UI/Toolbar/ToolbarToggleButton.prefab | 331 +++++++++++++++++ .../Toolbar/ToolbarToggleButton.prefab.meta | 7 + .../Resources/Prefabs/UI/Toolbar/images.meta | 8 + .../UI/Toolbar/images/ic_brush_default.png | Bin 0 -> 506 bytes .../Toolbar/images/ic_brush_default.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_brush_medium.png | Bin 0 -> 587 bytes .../Toolbar/images/ic_brush_medium.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_brush_small.png | Bin 0 -> 552 bytes .../UI/Toolbar/images/ic_brush_small.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_camera_front_off.png | Bin 0 -> 514 bytes .../images/ic_camera_front_off.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_camera_front_on.png | Bin 0 -> 635 bytes .../images/ic_camera_front_on.png.meta | 166 +++++++++ .../Toolbar/images/ic_camera_quarter_off.png | Bin 0 -> 606 bytes .../images/ic_camera_quarter_off.png.meta | 166 +++++++++ .../Toolbar/images/ic_camera_quarter_on.png | Bin 0 -> 678 bytes .../images/ic_camera_quarter_on.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_camera_top_off.png | Bin 0 -> 507 bytes .../Toolbar/images/ic_camera_top_off.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_camera_top_on.png | Bin 0 -> 644 bytes .../Toolbar/images/ic_camera_top_on.png.meta | 166 +++++++++ .../Prefabs/UI/Toolbar/images/ic_chapture.png | Bin 0 -> 611 bytes .../UI/Toolbar/images/ic_chapture.png.meta | 143 ++++++++ .../Prefabs/UI/Toolbar/images/ic_copy.png | Bin 0 -> 658 bytes .../UI/Toolbar/images/ic_copy.png.meta | 166 +++++++++ .../Prefabs/UI/Toolbar/images/ic_delete.png | Bin 0 -> 587 bytes .../UI/Toolbar/images/ic_delete.png.meta | 166 +++++++++ .../Prefabs/UI/Toolbar/images/ic_move.png | Bin 0 -> 806 bytes .../UI/Toolbar/images/ic_move.png.meta | 166 +++++++++ .../UI/Toolbar/images/ic_record_off.png | Bin 0 -> 519 bytes .../UI/Toolbar/images/ic_record_off.png.meta | 143 ++++++++ .../UI/Toolbar/images/ic_record_on.png | Bin 0 -> 646 bytes .../UI/Toolbar/images/ic_record_on.png.meta | 143 ++++++++ .../Prefabs/UI/Toolbar/images/ic_rotation.png | Bin 0 -> 741 bytes .../UI/Toolbar/images/ic_rotation.png.meta | 166 +++++++++ .../Prefabs/UI/Toolbar/images/ic_scale.png | Bin 0 -> 769 bytes .../UI/Toolbar/images/ic_scale.png.meta | 166 +++++++++ .../Prefabs/UI/Toolbar/images/ic_select.png | Bin 0 -> 938 bytes .../UI/Toolbar/images/ic_select.png.meta | 166 +++++++++ Assets/Resources/Prefabs/UI/Tooltip.meta | 8 + .../Prefabs/UI/Tooltip/Tooltip.prefab | 214 +++++++++++ .../Prefabs/UI/Tooltip/Tooltip.prefab.meta | 7 + Assets/Scenes/Main.unity | 127 +++++++ Assets/Scripts/SampleProject/AppMain.cs | 4 +- .../Scripts/UVC/Locale/LocalizationManager.cs | 4 +- .../Scripts/UVC/UI/Commands/ActionCommand.cs | 104 ++++++ .../UVC/UI/Commands/ActionCommand.cs.meta | 2 + .../UVC/UI/Commands/ChangeLanguageCommand.cs | 31 +- .../UVC/UI/Commands/DebugLogCommand.cs | 9 +- Assets/Scripts/UVC/UI/Commands/ICommand.cs | 9 +- .../Mono/ChangeLanguageCommandMono.cs | 2 +- .../UI/Commands/Mono/MonoBehaviourCommand.cs | 5 +- .../Mono/QuitApplicationCommandMono.cs | 2 +- .../UVC/UI/Commands/QuitApplicationCommand.cs | 19 +- .../Scripts/UVC/UI/Menu/TopMenuController.cs | 18 +- Assets/Scripts/UVC/UI/Menu/TopMenuModel.cs | 18 +- Assets/Scripts/UVC/UI/Menu/TopMenuView.cs | 2 +- Assets/Scripts/UVC/UI/Modal/Alert.cs | 79 +--- Assets/Scripts/UVC/UI/Modal/Confirm.cs | 107 ++---- Assets/Scripts/UVC/UI/Modal/ModalContent.cs | 57 +-- Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs | 2 +- .../UVC/UI/ToolBar/ToolbarButtonBase.cs | 34 +- .../UVC/UI/ToolBar/ToolbarExpandableButton.cs | 26 +- .../Scripts/UVC/UI/ToolBar/ToolbarManager.cs | 100 ----- .../UVC/UI/ToolBar/ToolbarRadioButton.cs | 49 ++- .../UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs | 2 +- .../UVC/UI/ToolBar/ToolbarSeparator.cs | 2 +- .../UVC/UI/ToolBar/ToolbarStandardButton.cs | 19 +- .../UVC/UI/ToolBar/ToolbarToggleButton.cs | 42 ++- Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs | 342 ++++++++++-------- .../UVC/UI/Toolbar/ToolbarController.cs | 171 +++++++++ .../ToolbarController.cs.meta} | 0 .../Toolbar.cs => Toolbar/ToolbarModel.cs} | 25 +- .../ToolbarModel.cs.meta} | 0 Assets/Scripts/UVC/UI/Tooltip.meta | 8 + .../UI/{ToolBar => Tooltip}/TooltipHandler.cs | 8 +- .../TooltipHandler.cs.meta | 0 .../Scripts/UVC/UI/Tooltip/TooltipManager.cs | 276 ++++++++++++++ .../UVC/UI/Tooltip/TooltipManager.cs.meta | 2 + 92 files changed, 5915 insertions(+), 530 deletions(-) create mode 100644 Assets/Resources/Prefabs/UI/Toolbar.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_default.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_default.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_medium.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_medium.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_small.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_small.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_off.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_off.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_on.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_on.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_top_off.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_top_off.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_top_on.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_top_on.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_chapture.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_chapture.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_copy.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_copy.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_off.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_off.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_on.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_on.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_rotation.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_rotation.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_scale.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_scale.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_select.png create mode 100644 Assets/Resources/Prefabs/UI/Toolbar/images/ic_select.png.meta create mode 100644 Assets/Resources/Prefabs/UI/Tooltip.meta create mode 100644 Assets/Resources/Prefabs/UI/Tooltip/Tooltip.prefab create mode 100644 Assets/Resources/Prefabs/UI/Tooltip/Tooltip.prefab.meta create mode 100644 Assets/Scripts/UVC/UI/Commands/ActionCommand.cs create mode 100644 Assets/Scripts/UVC/UI/Commands/ActionCommand.cs.meta delete mode 100644 Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs create mode 100644 Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs rename Assets/Scripts/UVC/UI/{ToolBar/ToolbarManager.cs.meta => Toolbar/ToolbarController.cs.meta} (100%) rename Assets/Scripts/UVC/UI/{ToolBar/Toolbar.cs => Toolbar/ToolbarModel.cs} (70%) rename Assets/Scripts/UVC/UI/{ToolBar/Toolbar.cs.meta => Toolbar/ToolbarModel.cs.meta} (100%) create mode 100644 Assets/Scripts/UVC/UI/Tooltip.meta rename Assets/Scripts/UVC/UI/{ToolBar => Tooltip}/TooltipHandler.cs (65%) rename Assets/Scripts/UVC/UI/{ToolBar => Tooltip}/TooltipHandler.cs.meta (100%) create mode 100644 Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs create mode 100644 Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs.meta diff --git a/Assets/Resources/Prefabs/UI/Toolbar.meta b/Assets/Resources/Prefabs/UI/Toolbar.meta new file mode 100644 index 00000000..e3e6e2b4 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a70aa5ec47caab4baa818285d286084 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab b/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab new file mode 100644 index 00000000..885ce3c1 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab @@ -0,0 +1,138 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1206908582753628858 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8849628700159893901} + - component: {fileID: 3825612598300117465} + - component: {fileID: 6541545458344494002} + - component: {fileID: 133595411402575730} + - component: {fileID: 4319427930282199054} + - component: {fileID: 7913949744637121483} + m_Layer: 5 + m_Name: Toolbar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8849628700159893901 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + 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: 0} + 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: -60} + m_SizeDelta: {x: 60, y: 300} + m_Pivot: {x: 0, y: 1} +--- !u!222 &3825612598300117465 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + m_CullTransparentMesh: 1 +--- !u!114 &6541545458344494002 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2c8047638e9a7ca4495254682609d580, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &133595411402575730 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60240c8d04420604681084344d3a0253, type: 3} + m_Name: + m_EditorClassIdentifier: + standardButtonPrefab: {fileID: 9218577172950644075, guid: 6ddcf28d4dbbab846af10da00d6a25e8, type: 3} + toggleButtonPrefab: {fileID: 8606839082655664627, guid: ef3f8393f35c1724ab83be37f239fe56, type: 3} + radioButtonPrefab: {fileID: 8606839082655664627, guid: 360200709f71d71409ed45c4389a07b8, type: 3} + expandableButtonPrefab: {fileID: 9218577172950644075, guid: b4b8fd38475f2a149a9a3f54ee662445, type: 3} + separatorPrefab: {fileID: 1459767928986708847, guid: 7483bbd02514516409d9966d8964bf32, type: 3} + subMenuPanelPrefab: {fileID: 5915359554380015081, guid: ff8ab25b7d27a5d49aefe48349c15fd9, type: 3} + toolbarContainer: {fileID: 8849628700159893901} + layoutGroup: {fileID: 7913949744637121483} +--- !u!114 &4319427930282199054 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + 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: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3} + m_Type: 1 + 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!114 &7913949744637121483 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1206908582753628858} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, 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: 0 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab.meta new file mode 100644 index 00000000..ab5f55aa --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/Toolbar.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5a23b2bd2bd04c045878e1a06b3b9aa2 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab new file mode 100644 index 00000000..8afb914a --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab @@ -0,0 +1,272 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6057772562893107812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3875727744418497138} + - component: {fileID: 340426463655327793} + - component: {fileID: 6424941990190813366} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &3875727744418497138 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + 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: 9063946921482485203} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &340426463655327793 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + m_CullTransparentMesh: 1 +--- !u!114 &6424941990190813366 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, 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_text: Button + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &9218577172950644075 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9063946921482485203} + - component: {fileID: 5596571647579825329} + - component: {fileID: 5161597693085375235} + - component: {fileID: 4379965520992721259} + - component: {fileID: 2720102606519727391} + m_Layer: 5 + m_Name: ToolbarExpandableButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9063946921482485203 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 3875727744418497138} + m_Father: {fileID: 0} + 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: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0, y: 1} +--- !u!222 &5596571647579825329 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + m_CullTransparentMesh: 1 +--- !u!114 &5161597693085375235 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + 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!114 &4379965520992721259 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 5161597693085375235} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2720102606519727391 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 266dd70132eff3d4eb32c995c009634a, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab.meta new file mode 100644 index 00000000..52a0cd20 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarExpandableButton.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b4b8fd38475f2a149a9a3f54ee662445 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab new file mode 100644 index 00000000..3caee806 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab @@ -0,0 +1,331 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1869750342838396698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9101619071920204464} + - component: {fileID: 4811966358153187933} + - component: {fileID: 7854806574037527308} + m_Layer: 5 + m_Name: Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &9101619071920204464 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + 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: 1059069334016684197} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 9, y: -0.5} + m_SizeDelta: {x: -28, y: -3} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4811966358153187933 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + m_CullTransparentMesh: 1 +--- !u!114 &7854806574037527308 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, 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_FontData: + m_Font: {fileID: 12800000, guid: 4d7bb720cabe1b14dadf1a0446fc5517, type: 3} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!1 &4502529336054035996 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2106966777486656531} + - component: {fileID: 3031794045290720662} + - component: {fileID: 856128947349540110} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2106966777486656531 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + 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: 117691393038772277} + m_Father: {fileID: 1059069334016684197} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!222 &3031794045290720662 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + m_CullTransparentMesh: 1 +--- !u!114 &856128947349540110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + 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: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + 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!1 &7951080877820295087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 117691393038772277} + - component: {fileID: 1908382904894419083} + - component: {fileID: 316978223752511866} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &117691393038772277 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + 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: 2106966777486656531} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1908382904894419083 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + m_CullTransparentMesh: 1 +--- !u!114 &316978223752511866 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + 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: 10901, guid: 0000000000000000f000000000000000, type: 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!1 &8606839082655664627 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1059069334016684197} + - component: {fileID: 5516198187994438965} + - component: {fileID: 4082783022810545647} + m_Layer: 5 + m_Name: ToolbarRadioButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1059069334016684197 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + 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: 2106966777486656531} + - {fileID: 9101619071920204464} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: -20, y: 20} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0, y: 1} +--- !u!114 &5516198187994438965 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, 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: 856128947349540110} + toggleTransition: 1 + graphic: {fileID: 316978223752511866} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 +--- !u!114 &4082783022810545647 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 266dd70132eff3d4eb32c995c009634a, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab.meta new file mode 100644 index 00000000..0ef7257a --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarRadioButton.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 360200709f71d71409ed45c4389a07b8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab new file mode 100644 index 00000000..7dc92837 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab @@ -0,0 +1,77 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1459767928986708847 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 539816085347750692} + - component: {fileID: 2193016365674033586} + - component: {fileID: 2266528321876069305} + m_Layer: 5 + m_Name: ToolbarSeparator + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &539816085347750692 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1459767928986708847} + 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: 0} + 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: 0} + m_SizeDelta: {x: 16, y: 1} + m_Pivot: {x: 0, y: 1} +--- !u!222 &2193016365674033586 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1459767928986708847} + m_CullTransparentMesh: 1 +--- !u!114 &2266528321876069305 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1459767928986708847} + 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.6132076, g: 0.6132076, b: 0.6132076, 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 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab.meta new file mode 100644 index 00000000..792e872c --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSeparator.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7483bbd02514516409d9966d8964bf32 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab new file mode 100644 index 00000000..c69aec5f --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab @@ -0,0 +1,272 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6057772562893107812 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3875727744418497138} + - component: {fileID: 340426463655327793} + - component: {fileID: 6424941990190813366} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &3875727744418497138 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + 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: 9063946921482485203} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &340426463655327793 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + m_CullTransparentMesh: 1 +--- !u!114 &6424941990190813366 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6057772562893107812} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, 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_text: Button + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 24 + m_fontSizeBase: 24 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &9218577172950644075 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9063946921482485203} + - component: {fileID: 5596571647579825329} + - component: {fileID: 5161597693085375235} + - component: {fileID: 4379965520992721259} + - component: {fileID: 2720102606519727391} + m_Layer: 5 + m_Name: ToolbarStandardButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9063946921482485203 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 3875727744418497138} + m_Father: {fileID: 0} + 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: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0, y: 1} +--- !u!222 &5596571647579825329 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + m_CullTransparentMesh: 1 +--- !u!114 &5161597693085375235 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + 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!114 &4379965520992721259 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + 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: 5161597693085375235} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2720102606519727391 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9218577172950644075} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 266dd70132eff3d4eb32c995c009634a, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab.meta new file mode 100644 index 00000000..705b2c0c --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarStandardButton.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6ddcf28d4dbbab846af10da00d6a25e8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab new file mode 100644 index 00000000..4a71322f --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab @@ -0,0 +1,104 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &5915359554380015081 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2183166441123322598} + - component: {fileID: 6840350081958449137} + - component: {fileID: 1807015620532569164} + - component: {fileID: 3873401652056562185} + m_Layer: 5 + m_Name: ToolbarSubMenuPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2183166441123322598 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5915359554380015081} + 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: 0} + 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: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6840350081958449137 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5915359554380015081} + m_CullTransparentMesh: 1 +--- !u!114 &1807015620532569164 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5915359554380015081} + 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: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3} + m_Type: 1 + 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!114 &3873401652056562185 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5915359554380015081} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, 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: 0 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab.meta new file mode 100644 index 00000000..60a9ae01 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarSubMenuPanel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ff8ab25b7d27a5d49aefe48349c15fd9 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab new file mode 100644 index 00000000..b8f62202 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab @@ -0,0 +1,331 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1869750342838396698 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9101619071920204464} + - component: {fileID: 4811966358153187933} + - component: {fileID: 7854806574037527308} + m_Layer: 5 + m_Name: Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &9101619071920204464 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + 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: 1059069334016684197} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 9, y: -0.5} + m_SizeDelta: {x: -28, y: -3} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4811966358153187933 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + m_CullTransparentMesh: 1 +--- !u!114 &7854806574037527308 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1869750342838396698} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, 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_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Toggle +--- !u!1 &4502529336054035996 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2106966777486656531} + - component: {fileID: 3031794045290720662} + - component: {fileID: 856128947349540110} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2106966777486656531 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + 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: 117691393038772277} + m_Father: {fileID: 1059069334016684197} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 1} +--- !u!222 &3031794045290720662 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + m_CullTransparentMesh: 1 +--- !u!114 &856128947349540110 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4502529336054035996} + 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: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + 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!1 &7951080877820295087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 117691393038772277} + - component: {fileID: 1908382904894419083} + - component: {fileID: 316978223752511866} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &117691393038772277 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + 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: 2106966777486656531} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1908382904894419083 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + m_CullTransparentMesh: 1 +--- !u!114 &316978223752511866 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7951080877820295087} + 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: 10901, guid: 0000000000000000f000000000000000, type: 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!1 &8606839082655664627 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1059069334016684197} + - component: {fileID: 5516198187994438965} + - component: {fileID: 4082783022810545647} + m_Layer: 5 + m_Name: ToolbarToggleButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1059069334016684197 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + 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: 2106966777486656531} + - {fileID: 9101619071920204464} + m_Father: {fileID: 0} + 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: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0, y: 1} +--- !u!114 &5516198187994438965 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, 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: 856128947349540110} + toggleTransition: 1 + graphic: {fileID: 316978223752511866} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 +--- !u!114 &4082783022810545647 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8606839082655664627} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 266dd70132eff3d4eb32c995c009634a, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab.meta b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab.meta new file mode 100644 index 00000000..4935586b --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/ToolbarToggleButton.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ef3f8393f35c1724ab83be37f239fe56 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images.meta b/Assets/Resources/Prefabs/UI/Toolbar/images.meta new file mode 100644 index 00000000..307184c3 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bd411013ea468aa45ac4cf19e84f3a93 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_default.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_brush_default.png new file mode 100644 index 0000000000000000000000000000000000000000..55ea2f363f39a17ddbbcd2ce3f3f5f318923a789 GIT binary patch literal 506 zcmV=870+UT zpS0R#cac92?CwA`F)?wT_`bjLJntLzYuCJM`UhOsU88zJxkb6REX&XHeA_g4bU~Ig z#?0$|xV~$XyrL0llG}s+u&IAE!7e$bEX#FMzo8L0L2i+z>9T1|U2upTqbfL5j!_eo zkYiK?rQ{fKK}k7AR8U%u5fjvqV?+eC z)%&I7#NbDb?6~BD_6rHp`wk){w^2Q#%n%tH(TdSt#^7Myt|*E~I&!8*&WF^Fn@2Yq z^9aWcDbu+~+T^OS75@QJrd1HX{Xi{p6*eB}oRsN`;EZ}WT)i5M`qA_kx&%Y&0TGNy znMOgpe+w*vkowt@GB@>$YR`K=MUGF4BuQdY=2rxEiEnolOPDjzVH9y`dSosMkk=x>qWTSpG4xmW) zXYWNaS?bC$MuLzF(AhU_GG>H?9AosdfX+Utn%r1IjwuyH@hPr)0erjxwmo!tQRGg8^9p2c*5eeZOkPFc< ze^95h7h{9)?p3r|b3?@3Q-1wTlO!3DEkVe=q2n7m4uwHnAo z_iE&OB+RAn!PJO-a!8e6--r_<-nJDLT#_)iWl5~R5!PCtV_tJflEg-SXiS}xFzP^z z+xK3`RL+uF|wUD9!0000aF5CsRY7=6V+8PvmO^hvaSn8Fe(!M0eL)x*}; z_M%$}c8HP4)3myOK=)PbLexmGPptiadr^^K7)Ak5+)BkHqD4`hEf(`x-?IaVc%7`} z$`UJJD3)Wio~Ja`rBeLt$0)&YI5?3!D-_&7lZ=43l)}A~q?9W4jF%*JLoYXiA*O-} z$z4<-<`wN0ZHjHShB87XM99QR+BM@P|k%$&^z`eL7=llKvUlff5O7tus2QbV}7R zRgzg>lI{^pc^qk}+_K&JzDpr#zD`<`Pz|Osca`VQ*IAaWV1Q-A`dO44iK-oxYZcs#qoJA-W1bSc}{%K!iX07*qoM6N<$ Ef)l>mAOHXW literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_off.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_off.png.meta new file mode 100644 index 00000000..a7246252 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_off.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 5ccf1d50090473443af9f7e0646f5219 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_camera_front_on_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 02926e36802bd9b4b8b9209c42f4ec08 + internalID: -114420605 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: eb653109d1125164ca2f72c796f053a4 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_camera_front_on_0: -114420605 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png new file mode 100644 index 0000000000000000000000000000000000000000..1dec1834d059a07673a27226065461c419224b6a GIT binary patch literal 635 zcmV->0)+jEP)?b2MRa1``=?WWkxh3aR}U zB?JU|v}hCgB^T05d;IS8`d(8;g5BNN4$l^kGk zaGKfLicq0&L-qQLQc6J|^u?G+Btk(6Bv>q#DVMvFQ;aAq5}g$Lj{YiyDIl0GT$A4w zB(Qj}0Knuz(j~CqGEviLmpVuu9UYIS-ZaK)F+@$2wrMuoEnNZ$CK9e(5Wk6%;OP7E zWa>Z)QBBf|K)F*vNe~aq=dUT5JeT!zS(07^UNo6JQ!bS&ZMWv_QlinQxSyKoj~ZO5 zJW{p#G_J?0Xl+=hMX`}Utu`TML~x#HqtTQ(G02XG)+q=Oxp+J-t4Xu@My4<(xGpx8 zM3;@AF5&=_x@0jSaf;a@OTl5fnBu{ijZuUXV}oo+6#q8ogMD$sBMbNn)+?Og_6gAg VE;9Zk#QOjM002ovPDHLkV1ksf3l9JQ literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png.meta new file mode 100644 index 00000000..2afce520 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_front_on.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 415fbd3c827e4e14f9518603c05a86ec +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_camera_front_off_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: e59c7b8f1cf935348a8adf9a8fbbe1e8 + internalID: -1817667921 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 9ff617165ac7a7248ab5d964a2b77434 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_camera_front_off_0: -1817667921 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png new file mode 100644 index 0000000000000000000000000000000000000000..f8d34c01ee2c11b706bcd2e3241e4ec0079b2dcd GIT binary patch literal 606 zcmV-k0-^nhP)jK~#7F?Uy}n z!Y~wop9=$Q44FF70TEh|xIy6t+@Np*xB+m3a)O2%^ai9is8kSPYPxk`V5r1GaNkRa zNCipkBx6--#|t%NC}AnI70y5 z4K!b<-9T`EWA zy$;DEJc8#(j6@t9Abh z`V`Zdm+MYF<&Wd)ORqut6PY!2T(iEM91?;wt>TM6Jed48G8bevPHitPN~5Ek>N6W8 zke*^%Q{kfZS(uneKxHBrE$VO5>BW2mqBxpBlu|mP2gPEeQ#*+`qGxHj+$F=s sxo+n37q_^+rnYTo_Eo1)C=~ylPre)$#Lrj4;{X5v07*qoM6N<$f)88-O#lD@ literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png.meta new file mode 100644 index 00000000..250fd0cb --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_off.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 544b8bd6eb388be428392fd3efe5f1c1 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_camera_quarter_on_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: fc33771a5f94bc645b11ad0c4ae695c9 + internalID: 2086692715 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: b06ee9312d5775b4a9e7ccc5ef0642d0 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_camera_quarter_on_0: 2086692715 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_on.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_camera_quarter_on.png new file mode 100644 index 0000000000000000000000000000000000000000..c198efcd4b5289806c6d9c3d07d9e87c1d21554b GIT binary patch literal 678 zcmV;X0$KfuP)fSUstXE2fRMi!h2tdQE@ zg%X6rYiW&5@&X?$q;hZXr#V>uo*J6BP7@3oDc5AsZ(-*FKb#+ZUJG*0lv`5wI%eRQih~c`F zLw&SEdzEoJj&cMiMG-kU_+><=^Pu`7OI(nKO5mdC@OJ$?hc zG*XfkK`B|Qy^`m7Vy2!dtt4S$sE22vo$Q$?=GYI0?@j=u@gm)BPvpU^kr<+d^wVhQ zZ!!#a)YGDqn23?7pkz`MT~{hqs8A>xuOe0iC8^YEFo|@=mkQPde~ZOZXNvoR;u~Ct z9402dVm8T9@G)IVK~#7F?Uv0= z!!Q(ppOZ_E9U#^4YF4p3rvngYnE3M=qPIe)qVORNOjVy*DP zRDQ7pvL3EdFy01qqf@;}m)lMQlh2VJ2;KcM|-kWLE7aQ{0o6CUqYU zYBCy)ZwG_*o0RgRe5$vWnidOZgvgncP|d>j=8qy$ojHFYwHSOC7cgm}sDTEU`OgpF zTCfp4POvFXNT8t1_;h<)D{(dclSb+hS1?#TpPH+pcO$>0rFQWJA xQ@U6Wod_xzW5YcEzyt`Fy8oBQZY{1HywozP7bYL!J!$u)Va{L z<$UijB^*faawi_z4?>!7mwbKq<6VvclFjCq0mk=?u{`H|5q=rYAz&-7TH06H@mP)(gunA7o zD;x|VsdD)MJa0){4+bA_eSHIsMiWdi5|qVcY=|ZjoFyh>BB~{*D<+dfR7ueDJgC*~ z5{t=@=;7fJgkd`@-e4fG(2igb zG+}FNTUj&`qdHVqmoy}VUPg!S?_!7F7XwKat5$ClNyRblgYk$)m_$s*+8~L`*bs}D zFSkt55-gQ`F(8tX$z&jx%WBn85~M!WXaphyP%dt@p0w6|>+1y^(O1xJzhDL_ihGpq zRM1*16bc2XR8DXwB0GIaJo)!}@8X=xtxmEM%ZqEQ%DT z+P_q=Ciqj#Gl?m4K~r!86Ncb0Dcr^Ef}_x8IyUim&&4Q`6Jz7!6n;GSIUld#jQ||r eD_GCuL~ft^0tZ{gam>B|0000v+NlD3JgC-+mwO0Tc8M+J3pHIMptiCH|Hzo&)CHQ0WVIH#z zDR4eU$QjOGcA~`CnY8tr2q#Qt4D~*lax?T>DHlKZbK^e@iG+wV=SWI z6sh)diD9JzU3p23|% zRI>}*ECqvYafpk1&bhF?cY0cDP`{fk(*>o(bTSzqLlFW^Yop3VfTV|rbrKVjfIeci zWtz$~KPJ4ZSQpA-2&>4*P}vZHqLvJ`a6h~SO1bE2VfYZoZ!~QQ{Zrs0i40X#!4q$R zh_azu^NuPMm5)JibgL}CEI&@((yDI0Rs7|65 z?e%wk@T3afB-d22Ln*OI?Pd^YtB!2a0#CdnsB(@f_M8Ouzl6a++0xcWS8|A;7D9k+@5cX zRauJH!8y0<^>-ag^B<+=Vkz}UzJGPR$tSl!$NADGH?C_R#}FtL$?NN}w~XO%#M(tF z5}>xXsV21rI?ksqqD3oLHWUJ76h%K$p-DVymeXXe6dwEj<Ca=sLT+@+##?VVr2O2O2b{r=Hu)Fw4d4F$xlhO|UopZ38v8&iX2F#^kC z1eWD32t=9AICo3DmqQK(&^atT9o2VsqF+!DL_A!18fyDx8Mv-%KRkpt%S#Rn=p5%k zKH7_sM36#U?ddvd-ANp$)uq6vP#Prxq5~m>)b-G65+N?nsD_eN51}~2yy6maUpwb_ s+xK5}?dimFH=Rx;p>>Bb7z}TXM^OsL5spo8yZ`_I07*qoM6N<$f&`Nkx&QzG literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_copy.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_copy.png.meta new file mode 100644 index 00000000..bd4b3f56 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_copy.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 857b963469c6ec54ea0485357c87309c +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_copy_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 0070e1f0126ca3e4daa31a3faba7fca5 + internalID: -2055758278 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: b859719aecf67dc4396c8a9a7bfcca65 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_copy_0: -2055758278 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..0d68effd39ab3715916d3eba4aa0db7e8dc23346 GIT binary patch literal 587 zcmV-R0<`^!P)cS0UiNPAf7C)nCB}q zBnAfU@CHptzhr3PwdJ3-uk9;<#qz%hU?SyNLkMUif?8=h2Ec9t0>dzTgA$+-F)q8`Ui=sAx4<9y{T7Ib59xXDb8V0I zyvl$|#E4=5yG9?k$~KNb6NLlYtquEV@(D|-u-6Rn{g{F!kye2J8 zJ}o_WqtWjXT_J&*TCGl(MA!lbMZ{?e-)>1M1B%L;)EmmQj&`yn!B_~V7e&KouvjeR Z@da}>mWwGpMb7{L002ovPDHLkV1f*d^!NY( literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png.meta new file mode 100644 index 00000000..02c3ceb8 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_delete.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 98513ecb40a66554bbe9964fe33e681b +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_delete_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: dd13c002d4f3fcb4c9203125e4c74030 + internalID: 1522047190 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 8835f23ccccd2ee4da0c2190ff304b87 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_delete_0: 1522047190 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png new file mode 100644 index 0000000000000000000000000000000000000000..13db25d03e58ef8a2a9d5159484a9004cba3efca GIT binary patch literal 806 zcmV+>1KIqEP)K~#7F?U=uB z(?Ar*-#Mw|4wWp$B~{eHo$7%Kv#}BW1O9}LjQJ0mj!cLRCdz-%ZZM@CnHo?~oXuP&>9&kQ-4lvrIIj!jk_gWql;Q+?3eBTekFpO-w zb_T#+(^%J&%7F9W(tA1~l>mi=AhmqIf05rah1~gvQ-oAMlZ63ua45s8)#}dHR^wX~ z4dZlmfB)beCe0h1TFH_UWFf%&a1&Vw@}gShU-0F>l6_5F`yjx9Dx`E4FMv}~q3o6d z)CiYK8geC|n5`JLR#M{>Mb8?CMe3v>3rD4--|xL=%s2&AJZ_x&{*TXOOBRxWB%E01 zT=(E*et#VQ{~iPZwL0)T&x+&mvt@f+*L5&QJBWZ+IQIQs8)N}z&)jHFgwrX4WUPA0 z`6S!tLM{q1pZsuY{w6$}Oi1AF-kI035R(VnxFx_)V2HZ`tvilqZERdSm5MP_9N+9U->lJ3PCA*JC+g}!ElGug~m=~Ew027}(mbY*w9 z5#8L3O$_M{2G&xAD-5^*vNag|d@Jr54u|p8)!(ne2dfgC65xGE!?W$iSr`r@anH1r zP(n;HUI|VaFbA2GpbWA|om(XaYbxJyrmK43KnEZxgQQx=BF_0*VHKt2pM_lF(AR|) kIPD@&Cf+Pns?=lY79tFQ`3@X|tN;K207*qoM6N<$f_iao`2YX_ literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png.meta new file mode 100644 index 00000000..4db52e5c --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_move.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 8ee861d387ee5cb4b977395964bcfd27 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_move_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: 144d020a34bb44e44a71508f48f87708 + internalID: -867214866 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: 41d013bc37e2481488b3a4739bcd6741 + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_move_0: -867214866 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_off.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_record_off.png new file mode 100644 index 0000000000000000000000000000000000000000..69315a2c90b52723b0ffaf1a79a1bb09c87da9c3 GIT binary patch literal 519 zcmV+i0{H!jP)&~89CD2Gza&1`_wN<=EeeNUmM%E1mu zZYzI>yhwg_J|W}$0uTrU0)bx*vuWZyOIocwftpAu71X3sFio?pC^q+a+l7N+V}O%^ zlvCv}$t);D#u?kbXsr{*V5K!%L2WeOJx=BM$(2%5>$Mu@q0NKVkf7Kw&))}1soH`< z2#&wr1aEn>x#?jY+0KnB#=3N2>~nO898vDUXi%=FGncuM-QveUtFkf<4(t{5jd#IL z=j>L9%bsc6tDq3)ef$&RF;CRK4$IxXJ}-hoTwH^N9N|S!>%#iA=|ym{m<_S? zZF;@!K`CG9;O_71Yk)^cQiyb^b<{TXcoih1d>dDd|J^qUMJ%cmR^ccxPFGAwPQk+{ zhzm`r#_`tbysCn-CG5^UOfyd|bB%#D#W;eKp+vRz^{%J+_DO*sfND7gjT5Cfg5L+u^l*Y>G>r9fYw2bLHk5$hOjSj6v zNMid*@~2~rDJ`g!k~Digx|M5dqaA7wT>I8?V%vNXVtDWrIcBm3Yn{n>HY(D$<~H~u zux8Q+gJUx98>6;SrWps(EQ`Z6hnkt01HGk8WQ4<$g)H z#Nw8VRV)M{`AQX1p~53mkOt~=8w9D-d6fs(mYAM6=-wHmRJZ#oObWaGGjR zn%jca8m-T^E?z@oh(il-=@pX1F;=m+^$P~Bf(#d$Le!5)vQQ28;3bpga&mR`cej_A z&<=6RVl!#6SVe1A((zA|41*xpKuHFJ!R77!#U_qu=00Vlp1k>uk0>g*NPcd@=7eJs ze0BeUk7Fip7e6>LmM%y?SwAagd9%#0bipLWE*_u7_8C&&m@Ca5z(;%=LU|VE= z>QeU-S+YYJ0iqAEC>|ZrzsSQwlBlJnrKM3=*#pmeq3IyBFT}TNvP8Gqg-NObW4fm` z^~f?60<{$4>vO6Bdi))V@wPs2i8ek&pEE`f&t~|D8?+bF9@OZ;!w_O7QH)*J?K#e~ z5n~J=z}|S?SrEsaw~n(Jpst0uo$hLfQ^QCpBO&GiQF4KvoS7JPoa8eEf2{L<;{pqW z5c1@tYeYs6>1wTO#p}@o8sd00+IJ!~7K8uN@An5v@k`u>g-t0HRlRpKf%Ews@kbZ5 zCr2IPLuduw7i$8QO1>a{1ju(k$RgGz$zt(+f?`6Ju_DlQ2UyPHo=L{0?s=YDJd0x| zl5!RmK84-*7Pi9YuC}cVG1k@B_|_%X*_WB6yDWZ=v%boFlB=z~^C`EDa-UaaZCmL< z6MvlZKq;N~f{Df7gjtbHi|uE&+@&n5;&$hT70XhTE%2pGv3(j-gY4`B?Fu_CMMw`ANt#;>A@?+ zA!>+8q`V`p~v}%00000NkvXXu0mjfRrFH} literal 0 HcmV?d00001 diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_rotation.png.meta b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_rotation.png.meta new file mode 100644 index 00000000..77a21696 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_rotation.png.meta @@ -0,0 +1,166 @@ +fileFormatVersion: 2 +guid: 86d02f3573fc0e143964145a452e2d16 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 8 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 64 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: WindowsStoreApps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: + - serializedVersion: 2 + name: ic_rotation_0 + rect: + serializedVersion: 2 + x: 0 + y: 0 + width: 40 + height: 40 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + customData: + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: b79ae7fd53f1ef149809a247e9d64dae + internalID: 1718713361 + vertices: [] + indices: + edges: [] + weights: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: db3359ad39ce6a449adb62fdb553889d + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: + ic_rotation_0: 1718713361 + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/Toolbar/images/ic_scale.png b/Assets/Resources/Prefabs/UI/Toolbar/images/ic_scale.png new file mode 100644 index 0000000000000000000000000000000000000000..4cdd5873fff5512639fbb5001f661a2fa7295cdb GIT binary patch literal 769 zcmV+c1OEJpP)Sqr;XzmMUO8pu) z*>Tv-XxmN3Occj50!O5j5n~{I-chkn;0DI9TQr$4R*thQ&0X!%G|i1EK3QAp!yPYy zC~=~7u~;sbDR`ok$~fl>yqx&hISMRqP+W#?itr`Vv$I5kCrKiuF?wo@A$RAlBk3rR zWdM47sK~lF>Vw>E3@lu1_X(WQ*P^&Nx#)k9E`cJ1jO*g459@B7+W#=yWzWD9Aw&!i zV9H>4E_zmYGyVSH8b|B4E)HIrIF2JaT-ztf@X~&mKi(tQ1i3p5^;KCy&Uuh3m1b}R zjv`Qq1oK<)#m=(|Gg0dI9kisiKnen!ix1nMp7h#|q-UbuM)8?`F%WVJ8aiy`)4k#n zT550C+|_?dN6?aE2%N)Oj1a>IoQJsXR>If}S`t7@9v}Z?r>F1fa)bvhV;|O! zZm^7c`yi>HT&Hz8vTo(yuwI#Mmn{ z0eCmx6jzR23)ckeEo1o9MmLpi0aitNgnfOb=NL?lI-Fe07?+Ic`$NPL)Rt`OBZ=pa zF1C&%SPAtPS7&o1|IvB`YuuG(AP<@BR8^BL_2FaZwUXeMW7Ha2V{=R!J=dKbZ9AWz zS8k1r0WbEJ{M&A#t5g4NXPNuFqobpv6|A6EdP&T%NUjP}INPYoy?1UM+nNooT1MZeW z01rqclH=?1#tyhuo17z{s^mwy_Oh`MT!(D{%2GFO!ki;4KvX7 z;ss+|gQ<&FWlTPF9NT3t1bMg#ccZ7qSWsuozX0jomr_+g!5)!==+#0qW6Ry=R&^*r z!u)*UmUA|a?h+Jq8B5ix2u zo9$d~Y8u@|DCV_VmxuBBR;z`vD;uqr%}!akaEwX@el+w~Fjhh{ve}uVR;%f;1Q1e? z&<_@<=yf{ktn1p|VEa&2Ns`yF#)wT>K_JyceN{+70#tLe*-0G8bVUi8*VmU{2HW>l zz1+#=Ch5<7h^91I<~rtfm;h9k0J1D?2LUIND|oF9veh(WJd^Q1N|FQxIb{HbbspB& zK~UHyg|E1ec*;RUTYs~AtUx_jAh&;if7ftbH<1qtRFYo-a@$e2GRTey#ok=b)lW&u z5fT&3WYqrEnsklvx$wi{?JD(8Pmk9T@nyQ!FsXMBbluQcLL??=+qOqlBP8pu#pi;c zyGQjJ5nrWu$2qBU?!OD`IbAo^@i(h10feJC4n*Y-JW7;4#>QrLJg?cFn==eq4mKha z6A>>Vf~_c;ksl{}<0yyb#6)gU&(0A zCL(&9)+ma+#RM@D!H7r{1XPQAFzLtlgED5zexu=uk=G_WAh diff --git a/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs b/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs new file mode 100644 index 00000000..94b91533 --- /dev/null +++ b/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs @@ -0,0 +1,104 @@ +using System; +using UnityEngine; + +namespace UVC.UI.Commands +{ + public class ActionCommand : ICommand + { + private readonly Action _action; + private readonly Action _actionWithParam; + + public ActionCommand(Action action) + { + _action = action ?? throw new ArgumentNullException(nameof(action)); + } + + public ActionCommand(Action actionWithParam) + { + _actionWithParam = actionWithParam ?? throw new ArgumentNullException(nameof(actionWithParam)); + } + + public void Execute(object parameter = null) + { + _action?.Invoke(); + _actionWithParam?.Invoke(parameter); + } + } + + // 제네릭 ActionCommand는 이미 파라미터를 생성자에서 받으므로, + // ICommand.Execute(object parameter)를 구현할 때 해당 파라미터를 사용하지 않거나, + // 혹은 Execute(object) 호출 시 전달된 파라미터로 내부 _parameter를 덮어쓰는 등의 정책을 정해야 합니다. + // 또는, ICommand 인터페이스를 고려할 수도 있습니다 (아래 2번 방법). + public class ActionCommand : ICommand // ICommand를 구현 + { + private readonly Action _action; + private readonly T _defaultParameter; + private bool _useDefaultParameterForParameterlessExecute; + + public ActionCommand(Action action) + { + _action = action ?? throw new ArgumentNullException(nameof(action)); + _useDefaultParameterForParameterlessExecute = true; // 기본적으로 default(T) 사용 + _defaultParameter = default(T); + } + + public ActionCommand(Action action, T defaultParameter, bool useDefaultForParameterless = true) + { + _action = action ?? throw new ArgumentNullException(nameof(action)); + _defaultParameter = defaultParameter; + _useDefaultParameterForParameterlessExecute = useDefaultForParameterless; + } + + // ICommand의 Execute(T parameter) 구현 + public void Execute(T parameter) + { + _action.Invoke(parameter); + } + + // ICommand 인터페이스에 의해 추가된 파라미터 없는 Execute() + // 기본 구현은 Execute(default(T))를 호출합니다. + // 이 메서드는 ICommand의 기본 인터페이스 메서드에 의해 제공되므로, + // 여기서 명시적으로 재정의할 필요는 없습니다. (void ICommand.Execute() => Execute(default(T));) + // 만약 다른 동작을 원한다면 여기서 재정의할 수 있습니다. + // public new void Execute() // 'new'는 인터페이스의 기본 구현을 숨기기 위함이 아님. + // { + // if (_useDefaultParameterForParameterlessExecute) + // { + // _action.Invoke(_defaultParameter); + // } + // else + // { + // // 또는 예외를 발생시키거나, 로깅 후 아무것도 하지 않음 + // Debug.LogWarning($"ActionCommand<{typeof(T).Name}>의 파라미터 없는 Execute()가 호출되었으나, 기본 파라미터 사용이 설정되지 않았습니다."); + // } + // } + + + // ICommand의 Execute(object parameter = null) 구현 + void ICommand.Execute(object parameter) // 명시적 인터페이스 구현 + { + if (parameter is T typedParameter) + { + Execute(typedParameter); + } + else if (parameter == null) + { + // 파라미터가 null로 전달된 경우, T의 기본값 또는 생성자에서 설정된 기본값을 사용할지 결정 + if (_useDefaultParameterForParameterlessExecute) + { + Execute(_defaultParameter); + } + else + { + // T가 참조 타입이면 default(T)는 null. 값 타입이면 0, false 등. + Execute(default(T)); + } + } + else + { + Debug.LogError($"ActionCommand<{typeof(T).Name}>.Execute(object): 잘못된 파라미터 타입입니다. 기대: {typeof(T).Name}, 실제: {parameter.GetType().Name}"); + // 예외를 발생시킬 수도 있습니다: throw new ArgumentException("잘못된 파라미터 타입입니다.", nameof(parameter)); + } + } + } +} diff --git a/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs.meta b/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs.meta new file mode 100644 index 00000000..eb2ecd9b --- /dev/null +++ b/Assets/Scripts/UVC/UI/Commands/ActionCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3f662cce09b4b4d48999758210c0ad4a \ No newline at end of file diff --git a/Assets/Scripts/UVC/UI/Commands/ChangeLanguageCommand.cs b/Assets/Scripts/UVC/UI/Commands/ChangeLanguageCommand.cs index 6335e50a..756244ae 100644 --- a/Assets/Scripts/UVC/UI/Commands/ChangeLanguageCommand.cs +++ b/Assets/Scripts/UVC/UI/Commands/ChangeLanguageCommand.cs @@ -1,4 +1,5 @@ -using UVC.Locale; +using UnityEngine; +using UVC.Locale; using UVC.Log; namespace UVC.UI.Commands @@ -14,17 +15,33 @@ namespace UVC.UI.Commands _languageCode = languageCode; } - public void Execute() + public void Execute(object parameter = null) { - LocalizationManager _localizationManager = LocalizationManager.Instance; - if (_localizationManager != null) + string targetLanguage = _languageCode; + + // Execute 호출 시 전달된 파라미터가 있다면 그것을 우선 사용 + if (parameter is string langCodeFromParam && !string.IsNullOrEmpty(langCodeFromParam)) { - _localizationManager.SetCurrentLanguage(_languageCode); - ULog.Debug($"언어가 {_languageCode}(으)로 변경되었습니다. (Command)"); + targetLanguage = langCodeFromParam; + Debug.Log($"ChangeLanguageCommand: 파라미터로 언어 코드 '{targetLanguage}' 사용."); + } + else if (!string.IsNullOrEmpty(_languageCode)) + { + Debug.Log($"ChangeLanguageCommand: 생성자에서 설정된 언어 코드 '{targetLanguage}' 사용."); } else { - ULog.Error("LocalizationManager가 ChangeLanguageCommand에 전달되지 않았습니다."); + Debug.LogError("ChangeLanguageCommand: 변경할 언어 코드가 지정되지 않았습니다."); + return; + } + + if (LocalizationManager.Instance != null) + { + LocalizationManager.Instance.SetCurrentLanguage(targetLanguage); + } + else + { + Debug.LogError("LocalizationManager 인스턴스를 찾을 수 없습니다."); } } } diff --git a/Assets/Scripts/UVC/UI/Commands/DebugLogCommand.cs b/Assets/Scripts/UVC/UI/Commands/DebugLogCommand.cs index 1d772395..a2c059ff 100644 --- a/Assets/Scripts/UVC/UI/Commands/DebugLogCommand.cs +++ b/Assets/Scripts/UVC/UI/Commands/DebugLogCommand.cs @@ -12,9 +12,14 @@ namespace UVC.UI.Commands _message = message; } - public void Execute() + public void Execute(object parameter = null) { - ULog.Debug(_message); + string finalMessage = _message; + if (parameter != null) + { + finalMessage += $", parameter: {parameter}"; + } + ULog.Debug(finalMessage); } } } diff --git a/Assets/Scripts/UVC/UI/Commands/ICommand.cs b/Assets/Scripts/UVC/UI/Commands/ICommand.cs index b0a37130..9677d9e4 100644 --- a/Assets/Scripts/UVC/UI/Commands/ICommand.cs +++ b/Assets/Scripts/UVC/UI/Commands/ICommand.cs @@ -2,6 +2,13 @@ { public interface ICommand { - void Execute(); + void Execute(object parameter = null); + } + + public interface ICommand : ICommand + { + void Execute(T parameter); + + void Execute() => Execute(default(T)); // 기본 Execute 구현 제공 가능 } } diff --git a/Assets/Scripts/UVC/UI/Commands/Mono/ChangeLanguageCommandMono.cs b/Assets/Scripts/UVC/UI/Commands/Mono/ChangeLanguageCommandMono.cs index ef0dd47f..05561261 100644 --- a/Assets/Scripts/UVC/UI/Commands/Mono/ChangeLanguageCommandMono.cs +++ b/Assets/Scripts/UVC/UI/Commands/Mono/ChangeLanguageCommandMono.cs @@ -6,7 +6,7 @@ namespace UVC.UI.Commands.Mono { public class ChangeLanguageCommandMono : MonoBehaviourCommand { - public override void Execute() + public override void Execute(object parameter = null) { //언어가 2개 인경우 switch 시킴 LocalizationManager _localizationManager = LocalizationManager.Instance; diff --git a/Assets/Scripts/UVC/UI/Commands/Mono/MonoBehaviourCommand.cs b/Assets/Scripts/UVC/UI/Commands/Mono/MonoBehaviourCommand.cs index 6b1471b6..3513aa66 100644 --- a/Assets/Scripts/UVC/UI/Commands/Mono/MonoBehaviourCommand.cs +++ b/Assets/Scripts/UVC/UI/Commands/Mono/MonoBehaviourCommand.cs @@ -2,11 +2,14 @@ namespace UVC.UI.Commands.Mono { + /// + /// Unity Inspector에서 버튼에 직접 할당할 수 있는 MonoBehaviour 기반의 명령 클래스입니다. + /// public class MonoBehaviourCommand : MonoBehaviour, ICommand { // MonoCommand는 MonoBehaviour를 상속받아 Unity의 생명주기를 활용할 수 있습니다. // ICommand 인터페이스를 구현하여 명령 패턴을 따릅니다. - public virtual void Execute() + public virtual void Execute(object parameter = null) { // 기본 실행 로직 (필요시 override 가능) Debug.Log("MonoCommand executed."); diff --git a/Assets/Scripts/UVC/UI/Commands/Mono/QuitApplicationCommandMono.cs b/Assets/Scripts/UVC/UI/Commands/Mono/QuitApplicationCommandMono.cs index d22d064e..3c9b9a37 100644 --- a/Assets/Scripts/UVC/UI/Commands/Mono/QuitApplicationCommandMono.cs +++ b/Assets/Scripts/UVC/UI/Commands/Mono/QuitApplicationCommandMono.cs @@ -5,7 +5,7 @@ namespace UVC.UI.Commands.Mono { public class QuitApplicationCommandMono : MonoBehaviourCommand { - public override void Execute() + public override void Execute(object parameter = null) { new QuitApplicationCommand().Execute(); } diff --git a/Assets/Scripts/UVC/UI/Commands/QuitApplicationCommand.cs b/Assets/Scripts/UVC/UI/Commands/QuitApplicationCommand.cs index 41076868..582c639b 100644 --- a/Assets/Scripts/UVC/UI/Commands/QuitApplicationCommand.cs +++ b/Assets/Scripts/UVC/UI/Commands/QuitApplicationCommand.cs @@ -1,17 +1,26 @@ using UnityEngine; -using UVC.Log; namespace UVC.UI.Commands { // 애플리케이션 종료 커맨드 public class QuitApplicationCommand : ICommand { - public void Execute() + public void Execute(object parameter = null) { - ULog.Debug("애플리케이션을 종료합니다."); - Application.Quit(); + // 파라미터는 여기서는 사용되지 않을 수 있음 + if (parameter != null) + { + Debug.Log($"QuitApplicationCommand 실행됨 (파라미터 무시됨: {parameter})"); + } + else + { + Debug.Log("QuitApplicationCommand 실행됨"); + } + #if UNITY_EDITOR - UnityEditor.EditorApplication.isPlaying = false; // 에디터에서 실행 중일 경우 플레이 모드 종료 + UnityEditor.EditorApplication.isPlaying = false; +#else + Application.Quit(); #endif } } diff --git a/Assets/Scripts/UVC/UI/Menu/TopMenuController.cs b/Assets/Scripts/UVC/UI/Menu/TopMenuController.cs index c29a9ab3..6ca362af 100644 --- a/Assets/Scripts/UVC/UI/Menu/TopMenuController.cs +++ b/Assets/Scripts/UVC/UI/Menu/TopMenuController.cs @@ -198,9 +198,13 @@ namespace UVC.UI.Menu new MenuItemData("file_new", "menu_file_new", subMenuItems: new List { new MenuItemData("file_new_project", "menu_file_new_project", new DebugLogCommand("새 프로젝트 선택됨 (Command 실행)")), - new MenuItemData("file_new_file", "menu_file_new_file", new DebugLogCommand("새 파일 선택됨 (Command 실행)")) + new MenuItemData("file_new_file", "menu_file_new_file", + new ActionCommand(() => Debug.Log("[SampleProject] 새 파일 선택됨"))) }), - new MenuItemData("file_open", "menu_file_open", new DebugLogCommand("파일 열기 선택됨 (Command 실행)"), isEnabled: false), // "파일 열기"는 비활성화 상태로 시작 + new MenuItemData("file_open", "menu_file_open", + new ActionCommand((path) => Debug.Log($"[SampleProject] 파일 열기 선택됨: {path}"), "sample.txt"), + commandParameter: "another_sample.txt", // 이 파라미터가 HandleMenuItemClicked에서 사용됨 + isEnabled: false), // "파일 열기"는 비활성화 상태로 시작 MenuItemData.CreateSeparator("file_sep1"), // 구분선 추가 new MenuItemData("file_save", "menu_file_save", command: new DebugLogCommand("저장 선택됨 (Command 실행)") , subMenuItems: new List { @@ -222,7 +226,7 @@ namespace UVC.UI.Menu model.MenuItems.Add(new MenuItemData("language", "menu_language", subMenuItems: new List { // 각 언어 메뉴 아이템에 ChangeLanguageCommand를 연결하여 언어 변경 기능 수행 - new MenuItemData("lang_ko", "menu_lang_korean", new ChangeLanguageCommand("ko-KR")), + new MenuItemData("lang_ko", "menu_lang_korean", new ChangeLanguageCommand("ko-KR"), commandParameter: "ko-KR"), new MenuItemData("lang_en", "menu_lang_english", new ChangeLanguageCommand("en-US")) // 필요에 따라 다른 언어들도 추가 가능 })); @@ -239,9 +243,13 @@ namespace UVC.UI.Menu // 클릭된 아이템이 구분선이거나 비활성화 상태인지 확인 if (clickedItemData.IsSeparator) { - // 구분선은 아무 동작도 하지 않음 + if (!clickedItemData.IsEnabled) + { + Debug.Log($"비활성화된 메뉴 아이템 클릭 시도: {clickedItemData.ItemId} (표시 키: {clickedItemData.DisplayNameKey})"); + } return; } + if (!clickedItemData.IsEnabled) { // 비활성화된 아이템 클릭 시 로그 (디버깅 목적) @@ -254,7 +262,7 @@ namespace UVC.UI.Menu // 메뉴 아이템에 연결된 Command가 있다면 실행 // Command가 null일 수 있으므로 null 조건부 연산자(?.) 사용 - clickedItemData.Command?.Execute(); + clickedItemData.Command?.Execute(clickedItemData.CommandParameter); } /// diff --git a/Assets/Scripts/UVC/UI/Menu/TopMenuModel.cs b/Assets/Scripts/UVC/UI/Menu/TopMenuModel.cs index 6b8b4145..174da5a3 100644 --- a/Assets/Scripts/UVC/UI/Menu/TopMenuModel.cs +++ b/Assets/Scripts/UVC/UI/Menu/TopMenuModel.cs @@ -16,7 +16,7 @@ namespace UVC.UI.Menu public string ItemId { get; private set; } /// - /// UI에 표시될 메뉴 아이템의 이름에 대한 다국어 처리 키입니다. + /// UI에 표시될 메뉴 아이템의 이름입니다. 다국어 키도 가능합니다. /// 이 키를 사용하여 실제 표시될 텍스트를 가져옵니다. /// public string DisplayNameKey { get; private set; } @@ -28,6 +28,12 @@ namespace UVC.UI.Menu /// public ICommand Command { get; private set; } + /// + /// 실행 시 전달될 파라미터입니다. + /// 이 파라미터는 에서 호출 시 사용될 수 있습니다. + /// + public object CommandParameter { get; set; } + /// /// 이 메뉴 아이템에 속한 하위 메뉴 아이템들의 목록입니다. /// 하위 메뉴가 없는 경우 빈 리스트입니다. @@ -51,16 +57,18 @@ namespace UVC.UI.Menu /// `MenuItemData` 클래스의 새 인스턴스를 초기화합니다. /// /// 메뉴 아이템의 고유 ID. - /// 표시 이름의 다국어 키. + /// 표시 이름. 표시 이름의 다국어 키도 가능. /// 실행할 명령 (선택 사항). + /// 커맨드에 전달할 파라미터 (선택 사항). /// 하위 메뉴 아이템 목록 (선택 사항). /// 구분선 여부 (선택 사항, 기본값: false). /// 활성화 상태 (선택 사항, 기본값: true). - public MenuItemData(string itemId, string displayNameKey, ICommand command = null, List subMenuItems = null, bool isSeparator = false, bool isEnabled = true) + public MenuItemData(string itemId, string displayName, ICommand command = null, object commandParameter = null, List subMenuItems = null, bool isSeparator = false, bool isEnabled = true) { ItemId = itemId; - DisplayNameKey = displayNameKey; + DisplayNameKey = displayName; Command = command; + CommandParameter = commandParameter; // 파라미터 저장 SubMenuItems = subMenuItems ?? new List(); // null인 경우 빈 리스트로 초기화 IsSeparator = isSeparator; IsEnabled = isEnabled; @@ -85,7 +93,7 @@ namespace UVC.UI.Menu public static MenuItemData CreateSeparator(string itemId = null) { // 구분선은 특정 동작이나 표시 이름이 필요 없으므로, displayNameKey는 비워두고 command는 null로 설정합니다. - return new MenuItemData(itemId ?? $"separator_{Guid.NewGuid()}", string.Empty, null, null, true); + return new MenuItemData(itemId ?? $"separator_{Guid.NewGuid()}", string.Empty, null, null, null, true); } } diff --git a/Assets/Scripts/UVC/UI/Menu/TopMenuView.cs b/Assets/Scripts/UVC/UI/Menu/TopMenuView.cs index 683a77e5..f2249af9 100644 --- a/Assets/Scripts/UVC/UI/Menu/TopMenuView.cs +++ b/Assets/Scripts/UVC/UI/Menu/TopMenuView.cs @@ -406,7 +406,7 @@ namespace UVC.UI.Menu { // LocalizationManager가 없는 경우, 키 값을 그대로 표시 (개발 중 확인 용도) ULog.Warning($"LocalizationManager 인스턴스가 없어 메뉴 아이템 텍스트를 키 값으로 설정합니다: {itemData.DisplayNameKey}"); - buttonText.text = $"[{itemData.DisplayNameKey}]"; + buttonText.text = itemData.DisplayNameKey; } } diff --git a/Assets/Scripts/UVC/UI/Modal/Alert.cs b/Assets/Scripts/UVC/UI/Modal/Alert.cs index 533b7090..7fbcf414 100644 --- a/Assets/Scripts/UVC/UI/Modal/Alert.cs +++ b/Assets/Scripts/UVC/UI/Modal/Alert.cs @@ -37,10 +37,10 @@ namespace UVC.UI.Modal /// ✨ 지정된 제목과 메시지로 알림창을 화면에 뿅! 하고 보여줘요. /// 사용자가 "확인" 버튼을 누를 때까지 코드는 여기서 잠시 멈춰 기다려요. /// - /// 알림창 맨 위에 크게 보일 '제목'이에요. - /// 알림창에 보여줄 '메시지 내용'이에요. - /// "확인" 버튼에 보여줄 글자예요. 아무것도 안 적으면 기본 글자("확인" 또는 설정된 언어)가 나와요. - /// 만약 특별히 만들어둔 알림창 디자인이 있다면, 그 파일 경로를 여기에 적어주세요. 없으면 기본 디자인을 사용해요. + /// 알림창 맨 위에 크게 보일 '제목'이에요. 다국어 키도 가능해요. + /// 알림창에 보여줄 '메시지 내용'이에요. 다국어 키도 가능해요. + /// "확인" 버튼에 보여줄 글자예요. 아무것도 안 적으면 기본 글자("확인" 또는 설정된 언어)가 나와요. 다국어 키도 가능해요. + /// 만약 특별히 만들어둔 알림창 디자인이 있다면, 그 파일 경로를 여기에 적어주세요. 없으면 기본 디자인을 사용해요. 다국어 키도 가능해요. /// 사용자가 확인 버튼을 누르면 완료되는 작업(UniTask)이에요. 특별한 값을 돌려주진 않아요. /// /// @@ -61,6 +61,19 @@ namespace UVC.UI.Modal /// await Alert.Show("저장 실패", "오류가 발생하여 저장하지 못했습니다.", "다시 시도"); /// // (다시 시도 로직 또는 다른 처리...) /// } + /// + /// // 예시: 퀘스트 완료 메시지를 현재 설정된 언어로 보여줍니다. + /// // titleLocalizationKey: "quest_completed_title" -> "퀘스트 완료" (한국어), "Quest Complete" (영어) + /// // messageLocalizationKey: "quest_completed_message" -> "{0} 퀘스트를 완료했습니다!" (한국어), "You have completed the {0} quest!" (영어) + /// // 여기서 {0} 부분은 실제 퀘스트 이름으로 바뀔 수 있도록 LocalizationManager에서 처리한다고 가정합니다. + /// + /// string localizedQuestName = LocalizationManager.Instance.GetString(questNameKey); // 예: "main_quest_01" -> "첫 번째 임무" + /// string formattedMessageKey = "quest_completed_message"; // 실제로는 메시지 포맷팅이 필요할 수 있음 + /// + /// // 실제 메시지는 LocalizationManager에서 포맷팅을 지원해야 함 + /// // 여기서는 간단히 키만 전달하는 것으로 가정 + /// await Alert.Show("quest_completed_title", formattedMessageKey, confirmButtonLocalizationKey: "ui_button_great"); + /// ULog.Debug("퀘스트 완료 알림을 플레이어가 확인했습니다."); /// } /// } /// @@ -76,15 +89,15 @@ namespace UVC.UI.Modal // ModalContent 레시피를 만들어요. 알림창은 취소 버튼이 필요 없으니 숨겨요. ModalContent content = new ModalContent(prefabPath) { - Title = title, - Message = message, + Title = LocalizationManager.Instance.GetString(title), + Message = LocalizationManager.Instance.GetString(message), ShowCancelButton = false, // Alert에서는 취소 버튼 숨김 }; // 확인 버튼 글자를 따로 정해줬다면 그걸로 설정해요. if (!string.IsNullOrEmpty(confirmButtonText)) { - content.ConfirmButtonText = confirmButtonText; + content.ConfirmButtonText = LocalizationManager.Instance.GetString(confirmButtonText); } // 아니면 ModalContent의 기본 설정(다국어 지원 "button_confirm" 키)을 따라요. // 만약 다른 기본 키를 쓰고 싶다면 여기서 설정할 수도 있어요. @@ -94,57 +107,5 @@ namespace UVC.UI.Modal // Alert은 사용자의 선택 결과(true/false)가 중요하지 않으므로, bool 타입으로 받고 결과는 무시해요. await Modal.Open(content); } - - /// - /// 🌍 다국어(여러 나라 언어)를 지원하는 알림창을 보여줘요. - /// 미리 준비된 '언어 키'를 알려주면, 게임 설정 언어에 맞는 글자를 자동으로 찾아서 보여줘요. - /// - /// 제목에 사용할 '언어 키'예요. (예: "alert_title_welcome") - /// 메시지 내용에 사용할 '언어 키'예요. (예: "alert_message_item_acquired") - /// 확인 버튼 글자에 사용할 '언어 키'예요. 안 적으면 기본 키("button_confirm")를 사용해요. - /// 특별한 알림창 디자인 파일 경로예요. 없으면 기본 디자인을 사용해요. - /// 사용자가 확인 버튼을 누르면 완료되는 작업(UniTask)이에요. - /// - /// - /// public class QuestManager : MonoBehaviour - /// { - /// public async void OnQuestCompleted(string questNameKey) - /// { - /// // 예시: 퀘스트 완료 메시지를 현재 설정된 언어로 보여줍니다. - /// // titleLocalizationKey: "quest_completed_title" -> "퀘스트 완료" (한국어), "Quest Complete" (영어) - /// // messageLocalizationKey: "quest_completed_message" -> "{0} 퀘스트를 완료했습니다!" (한국어), "You have completed the {0} quest!" (영어) - /// // 여기서 {0} 부분은 실제 퀘스트 이름으로 바뀔 수 있도록 LocalizationManager에서 처리한다고 가정합니다. - /// - /// string localizedQuestName = LocalizationManager.Instance.GetString(questNameKey); // 예: "main_quest_01" -> "첫 번째 임무" - /// string formattedMessageKey = "quest_completed_message"; // 실제로는 메시지 포맷팅이 필요할 수 있음 - /// - /// // 실제 메시지는 LocalizationManager에서 포맷팅을 지원해야 함 - /// // 여기서는 간단히 키만 전달하는 것으로 가정 - /// await Alert.ShowLocalized("quest_completed_title", formattedMessageKey, confirmButtonLocalizationKey: "ui_button_great"); - /// ULog.Debug("퀘스트 완료 알림을 플레이어가 확인했습니다."); - /// } - /// } - /// - /// - public static async UniTask ShowLocalized( - string titleLocalizationKey, - string messageLocalizationKey, - string confirmButtonLocalizationKey = null, - string customPrefabPath = null) - { - // 언어 키를 사용해서 실제 보여줄 글자들을 가져와요. - string title = LocalizationManager.Instance.GetString(titleLocalizationKey); - string message = LocalizationManager.Instance.GetString(messageLocalizationKey); - string confirmText = null; - - if (!string.IsNullOrEmpty(confirmButtonLocalizationKey)) - { - confirmText = LocalizationManager.Instance.GetString(confirmButtonLocalizationKey); - } - // confirmText가 null (따로 안 정해줬으면)이면, Show() 메서드 안에서 ModalContent의 기본 글자 로직이 알아서 처리해줘요. - - // 준비된 글자들로 알림창을 보여달라고 Show()에게 다시 부탁해요. - await Show(title, message, confirmText, customPrefabPath); - } } } \ No newline at end of file diff --git a/Assets/Scripts/UVC/UI/Modal/Confirm.cs b/Assets/Scripts/UVC/UI/Modal/Confirm.cs index ff5e8e9f..04115173 100644 --- a/Assets/Scripts/UVC/UI/Modal/Confirm.cs +++ b/Assets/Scripts/UVC/UI/Modal/Confirm.cs @@ -54,12 +54,12 @@ namespace UVC.UI.Modal /// ✨ 지정된 제목과 메시지로 확인창을 화면에 뿅! 하고 보여줘요. /// 사용자가 "확인" 또는 "취소" 버튼을 누를 때까지 코드는 여기서 잠시 멈춰 기다려요. /// - /// 확인창 맨 위에 크게 보일 '제목'이에요. - /// 확인창에 보여줄 '질문 또는 메시지 내용'이에요. - /// "확인" 버튼에 보여줄 글자예요. 안 적으면 기본 글자("확인")가 나와요. - /// "취소" 버튼에 보여줄 글자예요. 안 적으면 기본 글자("취소")가 나와요. - /// 특별히 만들어둔 확인창 디자인 파일 경로예요. 없으면 기본 디자인을 사용해요. - /// 사용자가 "확인"을 누르면 true, "취소"를 누르면 false를 돌려주는 작업(UniTask<bool>)이에요. + /// 확인창 맨 위에 크게 보일 '제목'이에요. 다국어 키도 가능해요. + /// 확인창에 보여줄 '질문 또는 메시지 내용'이에요. 다국어 키도 가능해요. + /// "확인" 버튼에 보여줄 글자예요. 안 적으면 기본 글자("확인")가 나와요. 다국어 키도 가능해요. + /// "취소" 버튼에 보여줄 글자예요. 안 적으면 기본 글자("취소")가 나와요. 다국어 키도 가능해요. + /// 특별히 만들어둔 확인창 디자인 파일 경로예요. 없으면 기본 디자인을 사용해요. 다국어 키도 가능해요. + /// 사용자가 "확인"을 누르면 true, "취소"를 누르면 false를 돌려주는 작업(UniTask)이에요. /// /// /// public class ShopManager : MonoBehaviour @@ -80,60 +80,7 @@ namespace UVC.UI.Modal /// { /// ULog.Debug($"{itemName} 구매를 취소했습니다."); /// } - /// } - /// } - /// - /// - public static async UniTask Show( - string title, - string message, - string confirmButtonText = null, - string cancelButtonText = null, - string customPrefabPath = null) - { - string prefabPath = string.IsNullOrEmpty(customPrefabPath) ? DefaultPrefabPath : customPrefabPath; - - // ModalContent 레시피를 만들어요. 확인창은 확인/취소 버튼이 모두 필요해요. - ModalContent content = new ModalContent(prefabPath) - { - Title = title, - Message = message, - ShowConfirmButton = true, // Confirm에서는 확인 버튼 항상 표시 - ShowCancelButton = true // Confirm에서는 취소 버튼 항상 표시 - }; - - // 확인 버튼 글자를 따로 정해줬다면 그걸로 설정해요. - if (!string.IsNullOrEmpty(confirmButtonText)) - { - content.ConfirmButtonText = confirmButtonText; - } - - // 취소 버튼 글자를 따로 정해줬다면 그걸로 설정해요. - if (!string.IsNullOrEmpty(cancelButtonText)) - { - content.CancelButtonText = cancelButtonText; - } - - // Modal 시스템에게 "이 레시피대로 모달 창 열어줘!" 라고 부탁하고, 사용자의 선택(true/false)을 기다려요. - return await Modal.Open(content); - } - - /// - /// 🌍 다국어(여러 나라 언어)를 지원하는 확인창을 보여줘요. - /// 미리 준비된 '언어 키'를 알려주면, 게임 설정 언어에 맞는 글자를 자동으로 찾아서 보여줘요. - /// - /// 제목에 사용할 '언어 키'예요. (예: "confirm_title_exit_game") - /// 메시지 내용에 사용할 '언어 키'예요. (예: "confirm_message_are_you_sure") - /// 확인 버튼 글자에 사용할 '언어 키'예요. 안 적으면 기본 키("button_confirm")를 사용해요. - /// 취소 버튼 글자에 사용할 '언어 키'예요. 안 적으면 기본 키("button_cancel")를 사용해요. - /// 특별한 확인창 디자인 파일 경로예요. 없으면 기본 디자인을 사용해요. - /// 사용자가 "확인"을 누르면 true, "취소"를 누르면 false를 돌려주는 작업(UniTask<bool>)이에요. - /// - /// - /// public class SettingsManager : MonoBehaviour - /// { - /// public async void OnResetSettings() - /// { + /// /// // 예시: 설정 초기화 전에 다국어로 확인을 받습니다. /// // titleLocalizationKey: "settings_reset_title" -> "설정 초기화" (한국어), "Reset Settings" (영어) /// // messageLocalizationKey: "settings_reset_confirm_message" -> "모든 설정을 초기화하시겠습니까?" (한국어), "Are you sure you want to reset all settings?" (영어) @@ -154,35 +101,43 @@ namespace UVC.UI.Modal /// { /// ULog.Debug("설정 초기화를 취소했습니다."); /// } + /// /// } /// } /// /// - public static async UniTask ShowLocalized( - string titleLocalizationKey, - string messageLocalizationKey, - string confirmButtonLocalizationKey = null, - string cancelButtonLocalizationKey = null, + public static async UniTask Show( + string title, + string message, + string confirmButtonText = null, + string cancelButtonText = null, string customPrefabPath = null) { - // 언어 키를 사용해서 실제 보여줄 글자들을 가져와요. - string title = LocalizationManager.Instance.GetString(titleLocalizationKey); - string message = LocalizationManager.Instance.GetString(messageLocalizationKey); - string confirmText = null; - string cancelText = null; + string prefabPath = string.IsNullOrEmpty(customPrefabPath) ? DefaultPrefabPath : customPrefabPath; - if (!string.IsNullOrEmpty(confirmButtonLocalizationKey)) + // ModalContent 레시피를 만들어요. 확인창은 확인/취소 버튼이 모두 필요해요. + ModalContent content = new ModalContent(prefabPath) { - confirmText = LocalizationManager.Instance.GetString(confirmButtonLocalizationKey); + Title = LocalizationManager.Instance.GetString(title), + Message = LocalizationManager.Instance.GetString(message), + ShowConfirmButton = true, // Confirm에서는 확인 버튼 항상 표시 + ShowCancelButton = true // Confirm에서는 취소 버튼 항상 표시 + }; + + // 확인 버튼 글자를 따로 정해줬다면 그걸로 설정해요. + if (!string.IsNullOrEmpty(confirmButtonText)) + { + content.ConfirmButtonText = LocalizationManager.Instance.GetString(confirmButtonText); } - if (!string.IsNullOrEmpty(cancelButtonLocalizationKey)) + // 취소 버튼 글자를 따로 정해줬다면 그걸로 설정해요. + if (!string.IsNullOrEmpty(cancelButtonText)) { - cancelText = LocalizationManager.Instance.GetString(cancelButtonLocalizationKey); + content.CancelButtonText = LocalizationManager.Instance.GetString(cancelButtonText); } - // 준비된 글자들로 확인창을 보여달라고 Show()에게 다시 부탁하고, 사용자의 선택을 기다려요. - return await Show(title, message, confirmText, cancelText, customPrefabPath); + // Modal 시스템에게 "이 레시피대로 모달 창 열어줘!" 라고 부탁하고, 사용자의 선택(true/false)을 기다려요. + return await Modal.Open(content); } } } \ No newline at end of file diff --git a/Assets/Scripts/UVC/UI/Modal/ModalContent.cs b/Assets/Scripts/UVC/UI/Modal/ModalContent.cs index 45b581a2..88ad9bfe 100644 --- a/Assets/Scripts/UVC/UI/Modal/ModalContent.cs +++ b/Assets/Scripts/UVC/UI/Modal/ModalContent.cs @@ -20,7 +20,7 @@ namespace UVC.UI.Modal /// }; /// /// // 이렇게 만든 레시피(myRecipe)를 Modal.Open()에 전달하면 모달이 뿅 나타나요! - /// // bool userChoseConfirm = await Modal.Open<bool>(myRecipe); + /// // bool userChoseConfirm = await Modal.Open(myRecipe); /// /// public class ModalContent @@ -37,11 +37,12 @@ namespace UVC.UI.Modal /// public string Message { get; set; } - private string _confirmButtonText; + private string _confirmButtonText = "확인"; /// /// ✅ '확인' 버튼에 보여줄 글자예요. /// 특별히 정해주지 않으면 기본적으로 "확인" (또는 설정된 언어에 맞게)이라고 나와요. /// 직접 "네", "저장하기", "출발!" 처럼 원하는 글자로 바꿀 수 있어요. + /// 다국어 키를 사용해서 설정할 수도 있어요. (예: "ui_button_confirm", "action_ok") /// public string ConfirmButtonText { @@ -50,19 +51,20 @@ namespace UVC.UI.Modal // _confirmButtonText가 명시적으로 설정되지 않았고, LocalizationManager 사용이 가능하다면 번역된 문자열을 반환 if (string.IsNullOrEmpty(_confirmButtonText) && LocalizationManager.Instance != null) { - return LocalizationManager.Instance.GetString("button_confirm"); + return LocalizationManager.Instance.GetString(_confirmButtonText); } // 명시적으로 설정된 값이 있거나 LocalizationManager를 사용할 수 없다면 해당 값 또는 기본 키 반환 - return !string.IsNullOrEmpty(_confirmButtonText) ? _confirmButtonText : "[button_confirm]"; + return _confirmButtonText; } set => _confirmButtonText = value; } - private string _cancelButtonText; + private string _cancelButtonText = "취소"; /// /// ❌ '취소' 버튼에 보여줄 글자예요. /// 특별히 정해주지 않으면 기본적으로 "취소" (또는 설정된 언어에 맞게)이라고 나와요. /// 직접 "아니요", "닫기", "나중에" 처럼 원하는 글자로 바꿀 수 있어요. + /// 다국어 키를 사용해서 설정할 수도 있어요. (예: "ui_button_cancel", "action_no") /// public string CancelButtonText { @@ -71,10 +73,10 @@ namespace UVC.UI.Modal // _cancelButtonText가 명시적으로 설정되지 않았고, LocalizationManager 사용이 가능하다면 번역된 문자열을 반환 if (string.IsNullOrEmpty(_cancelButtonText) && LocalizationManager.Instance != null) { - return LocalizationManager.Instance.GetString("button_cancel"); + return LocalizationManager.Instance.GetString(_cancelButtonText); } // 명시적으로 설정된 값이 있거나 LocalizationManager를 사용할 수 없다면 해당 값 또는 기본 키 반환 - return !string.IsNullOrEmpty(_cancelButtonText) ? _cancelButtonText : "[button_cancel]"; + return _cancelButtonText; } set => _cancelButtonText = value; } @@ -122,46 +124,7 @@ namespace UVC.UI.Modal PrefabPath = prefabPath; // Title, Message 등 다른 텍스트 속성도 필요한 경우 여기서 기본 다국어 키를 사용하여 초기화할 수 있습니다. // 예: Title = LocalizationManager.Instance.GetString("default_modal_title"); - } - - /// - /// 🔑 '확인' 버튼의 글자를 다국어 키를 사용해서 설정해요. - /// 게임이 여러 언어를 지원할 때 유용해요. - /// - /// 미리 정해둔 다국어 키 (예: "ui_button_yes", "action_save") - public void SetConfirmButtonTextFromKey(string localizationKey) - { - // 직접 값을 설정하는 대신, 키를 저장하고 getter에서 처리하도록 할 수도 있으나, - // 현재 구조에서는 setter를 통해 LocalizationManager.GetString을 호출하는 것이 더 간단합니다. - // 다만, 이 경우 인스턴스 생성 시점의 언어에 고정될 수 있으므로, - // 아래와 같이 getter에서 매번 가져오도록 하는 것이 언어 변경에 동적으로 반응합니다. - // 여기서는 명시적 설정을 위해 _confirmButtonText를 사용합니다. - // 만약 항상 최신 언어를 반영해야 한다면, _confirmButtonTextKey 와 같은 필드를 두고 getter에서 처리해야 합니다. - if (LocalizationManager.Instance != null) - { - _confirmButtonText = LocalizationManager.Instance.GetString(localizationKey); - } - else - { - _confirmButtonText = $"[{localizationKey}]"; - } - } - - /// - /// 🔑 '취소' 버튼의 글자를 다국어 키를 사용해서 설정해요. - /// - /// 미리 정해둔 다국어 키 (예: "ui_button_no", "action_cancel") - public void SetCancelButtonTextFromKey(string localizationKey) - { - if (LocalizationManager.Instance != null) - { - _cancelButtonText = LocalizationManager.Instance.GetString(localizationKey); - } - else - { - _cancelButtonText = $"[{localizationKey}]"; - } - } + } /// /// 🚀 모달 창이 화면에 나타나기 *직전*에 이 레시피가 할 일을 정해요. (비동기 작업 가능) diff --git a/Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs b/Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs index 8011e66d..351e53e7 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/IToolbarItem.cs @@ -1,4 +1,4 @@ -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 툴바에 추가될 수 있는 모든 항목(버튼, 구분선 등)의 기본 인터페이스입니다. diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs index 8b15c931..db881f9d 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarButtonBase.cs @@ -1,7 +1,8 @@ using System; using UnityEngine; +using UVC.UI.Commands; -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 모든 버튼의 기본 추상 클래스입니다. @@ -11,7 +12,7 @@ namespace UVC.UI.ToolBar { public event Action OnStateChanged; // 상태 변경 알림 이벤트 - private string _text; + protected string _text; public string Text { get => _text; @@ -25,21 +26,21 @@ namespace UVC.UI.ToolBar } } - private Sprite _icon; - public Sprite Icon + protected string _iconSpritePath; + public string IconSpritePath { - get => _icon; + get => _iconSpritePath; set { - if (_icon != value) + if (_iconSpritePath != value) { - _icon = value; + _iconSpritePath = value; OnStateChanged?.Invoke(); } } } - private bool _isEnabled = true; + protected bool _isEnabled = true; public bool IsEnabled { get => _isEnabled; @@ -53,7 +54,7 @@ namespace UVC.UI.ToolBar } } - private string _tooltipKey; // 툴팁 다국어 키 + protected string _tooltipKey; // 툴팁 다국어 키 public string TooltipKey { get => _tooltipKey; @@ -69,9 +70,20 @@ namespace UVC.UI.ToolBar } } - public Action OnClick { get; set; } + public ICommand ClickCommand { get; set; } - public abstract void ExecuteClick(); + /// + /// 버튼 클릭 로직을 실행합니다. + /// 이 메서드는 일반적으로 UI 이벤트에 의해 호출됩니다. + /// + /// 커맨드에 전달할 파라미터입니다. + public virtual void ExecuteClick(object parameter = null) + { + if (IsEnabled && ClickCommand != null) + { + ClickCommand.Execute(parameter); // 커맨드에 파라미터 전달 + } + } // OnStateChanged 이벤트를 외부에서 강제로 발생시켜야 할 때 사용 (예: 복합적인 상태 변경 후) public void NotifyStateChanged() diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs index 1475cdf9..2d88da2d 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarExpandableButton.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 클릭 시 하위 버튼 그룹을 확장하여 보여주는 버튼입니다. @@ -22,12 +22,22 @@ namespace UVC.UI.ToolBar SubButtons = new List(); } - public override void ExecuteClick() + // 주 버튼 클릭 시 하위 메뉴를 토글하는 동작은 View에서 처리될 수 있고, + // ClickCommand는 주 버튼 자체의 액션(있다면)을 정의합니다. + // 또는 ClickCommand가 하위 메뉴 토글 로직을 포함할 수도 있습니다. + // 여기서는 ClickCommand는 주 버튼의 고유 액션, 하위 메뉴 토글은 View의 역할로 가정합니다. + public override void ExecuteClick(object parameter = null) { - if (IsEnabled) - { - OnClick?.Invoke(); - } + if (!IsEnabled) return; + + // ClickCommand는 주 버튼 자체의 액션 (예: 상태 변경, 특정 기능 수행) + ClickCommand?.Execute(parameter); + + // 하위 메뉴를 여는 동작은 보통 View에서 이 버튼 클릭 시 별도로 처리합니다. + // OnClick (이제 ClickCommand)이 그 역할을 할 수도 있지만, + // View에서 직접 ToggleSubMenu를 호출하는 것이 더 명확할 수 있습니다. + // ToolbarView의 SetupButtonVisualsAndInteractions에서 expandableModel.ExecuteClick() 후 + // ToggleSubMenu()를 호출하는 현재 구조를 유지할 수 있습니다. } public void SelectSubButton(ToolbarButtonBase selectedSubButton) @@ -40,9 +50,9 @@ namespace UVC.UI.ToolBar this.Text = selectedSubButton.Text; // Setter가 OnStateChanged 호출 (단, Text가 실제로 변경되어야 함) changed = true; } - if (this.Icon != selectedSubButton.Icon) + if (this.IconSpritePath != selectedSubButton.IconSpritePath) { - this.Icon = selectedSubButton.Icon; // Setter가 OnStateChanged 호출 + this.IconSpritePath = selectedSubButton.IconSpritePath; // Setter가 OnStateChanged 호출 changed = true; } diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs deleted file mode 100644 index 350a7dc5..00000000 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs +++ /dev/null @@ -1,100 +0,0 @@ -using UnityEngine; -using UVC.Locale; - -namespace UVC.UI.ToolBar -{ - public class ToolbarManager : MonoBehaviour - { - public Toolbar mainToolbar; - public ToolbarView mainToolbarView; // Unity 에디터에서 할당 - public Transform toolbarContainer; // Unity 에디터에서 할당 (툴바 UI가 생성될 부모) - // 여기에 HorizontalLayoutGroup 또는 VerticalLayoutGroup을 추가하는 것을 권장합니다. - - // 버튼 프리팹들은 ToolbarView로 옮겨서 관리하는 것이 더 깔끔할 수 있습니다. - // 현재는 ToolbarManager에서 할당하여 ToolbarView로 전달하는 방식입니다. - public GameObject standardButtonPrefab; - public GameObject toggleButtonPrefab; - public GameObject radioButtonPrefab; - public GameObject expandableButtonPrefab; - public GameObject separatorPrefab; - public GameObject subMenuPanelPrefab; - - - void Start() - { - mainToolbar = new Toolbar(); - - // ToolbarView에 프리팹 설정 - if (mainToolbarView != null) - { - mainToolbarView.standardButtonPrefab = standardButtonPrefab; - mainToolbarView.toggleButtonPrefab = toggleButtonPrefab; - mainToolbarView.radioButtonPrefab = radioButtonPrefab; - mainToolbarView.expandableButtonPrefab = expandableButtonPrefab; - mainToolbarView.separatorPrefab = separatorPrefab; - mainToolbarView.subMenuPanelPrefab = subMenuPanelPrefab; - } - else - { - Debug.LogError("ToolbarView가 할당되지 않았습니다."); - return; - } - - // --- 툴바 모델 구성 --- - // "저장" 대신 다국어 키 "button_save" 사용 - mainToolbar.AddStandardButton("button_save", null, () => Debug.Log("저장 버튼 클릭됨"), "tooltip_save_button"); - - // "음소거" 대신 다국어 키 "button_mute" 사용 - mainToolbar.AddToggleButton("button_mute", false, null, (isSelected) => Debug.Log($"음소거: {isSelected}"), "tooltip_mute_button"); - - mainToolbar.AddSeparator(); - - // "펜" 대신 다국어 키 "tool_pen" 사용 - mainToolbar.AddRadioButton("ToolGroup", "tool_pen", true, null, (isSelected) => { if (isSelected) Debug.Log("펜 도구 선택됨"); }, "tooltip_pen_tool"); - // "지우개" 대신 다국어 키 "tool_eraser" 사용 - mainToolbar.AddRadioButton("ToolGroup", "tool_eraser", false, null, (isSelected) => { if (isSelected) Debug.Log("지우개 도구 선택됨"); }, "tooltip_eraser_tool"); - - mainToolbar.AddSeparator(); - - // "브러시 크기" 대신 다국어 키 "button_brush_size" 사용 - var expandableBtnModel = mainToolbar.AddExpandableButton("button_brush_size", null, null, "tooltip_brush_size"); - // 하위 버튼도 다국어 키 사용 - var smallBrush = new ToolbarStandardButton { Text = "brush_size_small", TooltipKey = "tooltip_brush_small" }; - expandableBtnModel.SubButtons.Add(smallBrush); - expandableBtnModel.SubButtons.Add(new ToolbarStandardButton { Text = "brush_size_medium", TooltipKey = "tooltip_brush_medium" }); - expandableBtnModel.OnSubButtonSelected = (selectedSubButton) => { - // selectedSubButton.Text 에는 이제 다국어 키가 들어있습니다. - // 실제 표시된 텍스트를 로그로 남기려면 LocalizationManager를 사용해야 합니다. - string localizedSubButtonText = LocalizationManager.Instance != null ? LocalizationManager.Instance.GetString(selectedSubButton.Text) : selectedSubButton.Text; - Debug.Log($"브러시 크기 '{localizedSubButtonText}' 선택됨 (주 버튼 업데이트)"); - }; - // --- 툴바 모델 구성 끝 --- - - - // ToolbarView 초기화 및 렌더링 - if (toolbarContainer != null) - { - mainToolbarView.Initialize(mainToolbar, toolbarContainer); - } - else - { - Debug.LogError("ToolbarContainer가 할당되지 않았습니다."); - } - - // 예시: 모델 상태를 코드로 변경하고 UI가 업데이트되는지 테스트 - // StartCoroutine(TestModelChange(saveBtnModel, muteToggleModel)); - } - - // System.Collections.IEnumerator TestModelChange(ToolbarStandardButton standard, ToolbarToggleButton toggle) - // { - // yield return new WaitForSeconds(2f); - // Debug.Log("모델 변경 테스트: 저장 버튼 비활성화 및 텍스트 변경"); - // standard.Text = "저장됨"; - // standard.IsEnabled = false; - // - // yield return new WaitForSeconds(2f); - // Debug.Log("모델 변경 테스트: 음소거 토글 상태 변경"); - // toggle.IsSelected = true; - // } - } -} diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs index 494d9f27..ca551d1e 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButton.cs @@ -1,4 +1,4 @@ -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 라디오 버튼 그룹 내에서 사용되는 버튼입니다. @@ -14,19 +14,46 @@ GroupName = groupName; } - public override void ExecuteClick() + public override void ExecuteClick(object parameter = null) { - if (IsEnabled) + if (!IsEnabled) return; + + bool wasSelected = IsSelected; + + if (RadioGroup != null) { - // 라디오 버튼은 직접 IsSelected를 토글하지 않고, 그룹에 의해 상태가 결정됩니다. - // 그룹이 SetSelected를 호출하면, 해당 버튼의 IsSelected가 true로 설정되고, - // 다른 버튼들은 false로 설정되면서 각자의 OnStateChanged 이벤트가 발생합니다. - RadioGroup?.SetSelected(this); - // OnClick은 그룹에 의해 선택이 확정되었을 때 호출되도록 RadioGroup.SetSelected 내부에서 처리하거나, - // 여기서 IsSelected 상태를 확인 후 호출할 수 있습니다. - // 현재 구조에서는 RadioGroup.SetSelected가 IsSelected를 변경하고, IsSelected의 setter가 OnStateChanged를 호출합니다. - // OnClick은 ToolbarToggleButton의 ExecuteClick에서 이미 호출될 수 있으므로 중복 호출을 피하거나 의도에 맞게 조정합니다. + // SetSelected는 IsSelected 상태를 변경하고, + // IsSelected setter는 OnToggleStateChanged 및 NotifyStateChanged를 호출합니다. + // OnToggle 콜백도 IsSelected setter 내부 또는 SetSelected 메서드 내에서 호출될 수 있습니다. + RadioGroup.SetSelected(this); } + else + { + // 그룹이 없는 라디오 버튼은 의미가 모호하므로, 단독으로 선택되는 것을 방지하거나 특별 처리. + // 여기서는 그룹이 없으면 아무것도 하지 않거나, 경고를 로깅할 수 있습니다. + UnityEngine.Debug.LogWarning($"ToolbarRadioButton '{Text}' (그룹: {GroupName})에 RadioGroup이 할당되지 않았습니다."); + // 또는 강제로 선택 상태로 만들고 콜백 호출 (기존 주석 참고) + // if (!IsSelected) // 현재 선택되지 않았다면 선택 + // { + // IsSelected = true; + // OnToggle?.Invoke(IsSelected); + // } + } + + // ClickCommand 실행 + // RadioGroup.SetSelected에 의해 IsSelected 상태가 변경된 후 실행됩니다. + // parameter가 null이 아니면 그것을 우선 사용하고, 아니면 현재 IsSelected 상태를 전달할 수 있습니다. + // 또는 버튼 자체를 파라미터로 전달하여 Command가 필요한 정보를 추출하도록 할 수도 있습니다. + object commandParameterToUse = parameter ?? this; // 예: 파라미터가 없으면 버튼 인스턴스 전달 + + // 라디오 버튼의 경우, ClickCommand는 주로 해당 버튼이 "선택되었을 때"의 액션을 정의합니다. + // 따라서 IsSelected가 true일 때만 Command를 실행하는 것이 일반적일 수 있습니다. + if (IsSelected) // 현재 버튼이 선택된 상태일 때만 Command 실행 + { + ClickCommand?.Execute(commandParameterToUse); + } + // 만약 선택 해제 시에도 Command를 실행해야 한다면 위 if 조건을 제거합니다. + // 혹은, 선택/해제 상태 모두에 대해 Command를 실행하되, Command 내부에서 IsSelected 값을 확인하도록 합니다. } } } diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs index 871b58e2..281e7fca 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarRadioButtonGroup.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 라디오 버튼들을 그룹으로 관리하여 하나만 선택되도록 합니다. diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs index d65f5100..a0fc0bc5 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarSeparator.cs @@ -1,4 +1,4 @@ -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 툴바 구분선을 나타냅니다. diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs index 96526350..208caa27 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarStandardButton.cs @@ -1,16 +1,19 @@ -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 일반적인 클릭 버튼입니다. /// public class ToolbarStandardButton : ToolbarButtonBase { - public override void ExecuteClick() - { - if (IsEnabled && OnClick != null) - { - OnClick.Invoke(); - } - } + // 생성자 또는 초기화 메서드가 있다면 ICommand를 받도록 수정 + // 예: public ToolbarStandardButton(ICommand command) { this.ClickCommand = command; } + + // ToolbarButtonBase의 ExecuteClick을 그대로 사용하거나, + // 필요시 override 할 수 있습니다. + // public override void ExecuteClick() + // { + // base.ExecuteClick(); // 기본 Command 실행 + // // 추가적인 StandardButton만의 로직 + // } } } diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs index 295847c6..84204ee0 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarToggleButton.cs @@ -1,6 +1,7 @@ using System; +using UnityEngine; -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { /// /// 클릭할 때마다 선택/해제 상태가 변경되는 토글 버튼입니다. @@ -9,6 +10,21 @@ namespace UVC.UI.ToolBar { public event Action OnToggleStateChanged; // IsSelected 변경 시 IsSelected 값을 전달하는 이벤트 + + protected string _offIconSpritePath; + public string OffIconSpritePath + { + get => _offIconSpritePath; + set + { + if (_offIconSpritePath != value) + { + _offIconSpritePath = value; + NotifyStateChanged(); + } + } + } + private bool _isSelected; public bool IsSelected { @@ -25,14 +41,28 @@ namespace UVC.UI.ToolBar } public Action OnToggle { get; set; } - public override void ExecuteClick() + public override void ExecuteClick(object parameter = null) { - if (IsEnabled) + if (!IsEnabled) return; + + if (parameter is bool newSelectedStateFromUI) { - IsSelected = !IsSelected; // IsSelected의 setter가 OnStateChanged를 호출 - OnClick?.Invoke(); // OnClick은 상태 변경과 별개로 클릭 시 항상 호출되도록 할 수 있음 - OnToggle?.Invoke(IsSelected); // 기존 OnToggle 로직 유지 + // UI로부터 직접 상태가 전달된 경우 (View의 onValueChanged 리스너) + // IsSelected 프로퍼티 setter가 OnToggle 및 NotifyStateChanged를 호출 + IsSelected = newSelectedStateFromUI; } + else + { + // 일반적인 ExecuteClick (파라미터 없거나 bool이 아님) - 기존 토글 로직 + IsSelected = !IsSelected; + } + + OnToggle?.Invoke(IsSelected); // IsSelected는 이미 위에서 최종 상태로 설정됨 + + // ClickCommand 실행. 필요하다면 IsSelected나 다른 값을 파라미터로 전달. + // 여기서는 parameter 인자로 받은 값을 우선 사용하고, 없으면 IsSelected를 사용. + object commandParameter = parameter ?? IsSelected; + ClickCommand?.Execute(commandParameter); } } } diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs b/Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs index f4500ae2..16d98d83 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs +++ b/Assets/Scripts/UVC/UI/ToolBar/ToolbarView.cs @@ -2,53 +2,109 @@ using TMPro; using UnityEngine; using UnityEngine.UI; +using UVC.Extension; using UVC.Locale; +using UVC.UI.Tooltip; -namespace UVC.UI.ToolBar +namespace UVC.UI.Toolbar { public class ToolbarView : MonoBehaviour { - public Toolbar ToolbarModel { get; private set; } + protected ToolbarModel ToolbarModel { get; private set; } + // 이제 이 프리팹들은 ToolbarView GameObject의 Inspector에서 직접 할당해야 합니다. public GameObject standardButtonPrefab; public GameObject toggleButtonPrefab; public GameObject radioButtonPrefab; public GameObject expandableButtonPrefab; public GameObject separatorPrefab; public GameObject subMenuPanelPrefab; - public GameObject tooltipPrefab; // 툴팁 UI 프리팹 - private Transform toolbarContainer; + public Transform toolbarContainer; + public LayoutGroup layoutGroup; // UI 요소와 모델을 매핑하여 상태 업데이트 시 사용 - private Dictionary _modelToGameObjectMap = new Dictionary(); + protected Dictionary _modelToGameObjectMap = new Dictionary(); - private GameObject _activeTooltipInstance; - private TextMeshProUGUI _tooltipTextElement; - private RectTransform _tooltipRectTransform; + // Canvas 참조 (Inspector에서 할당하거나 GetComponentInParent 등으로 찾기) + protected Canvas rootCanvas; - public void Initialize(Toolbar toolbarModel, Transform container) + protected virtual void Awake() { - ToolbarModel = toolbarModel; - toolbarContainer = container; - // UI 레이아웃: toolbarContainer에 VerticalLayoutGroup 또는 HorizontalLayoutGroup 컴포넌트를 추가하고 - // 자식 크기 제어 (Child Force Expand 등) 옵션을 조정하면 UI 요소들이 자동으로 정렬됩니다. - // 예: var layoutGroup = toolbarContainer.GetComponent(); - // if (layoutGroup == null) layoutGroup = toolbarContainer.gameObject.AddComponent(); - // layoutGroup.childControlHeight = true; layoutGroup.childControlWidth = false; // 예시 설정 - - RenderToolbar(); - - if (tooltipPrefab != null) + if (toolbarContainer == null) { - _activeTooltipInstance = Instantiate(tooltipPrefab, transform); // ToolbarView의 자식으로 생성 (Canvas 내 다른 곳이어도 됨) - _tooltipTextElement = _activeTooltipInstance.GetComponentInChildren(); - _tooltipRectTransform = _activeTooltipInstance.GetComponent(); - _activeTooltipInstance.SetActive(false); // 처음에는 숨김 + toolbarContainer = GetComponent(); + } + if (toolbarContainer == null) + { + toolbarContainer = GetComponentInChildren(); + } + + if (layoutGroup == null) + { + layoutGroup = toolbarContainer.gameObject.GetComponent(); + } + if (layoutGroup == null) + { + layoutGroup = toolbarContainer.gameObject.AddComponent(); + } + + + // TooltipVisualManager 초기화 + // rootCanvas가 Inspector에서 할당되지 않았다면 여기서 찾아야 합니다. + if (rootCanvas == null) + { + rootCanvas = GetComponentInParent(); + if (rootCanvas == null) + { + // 최상위 Canvas를 찾기 위한 더 강력한 방법 (예: FindObjectOfType() 후 필터링) + // 또는 씬에 하나의 메인 Canvas만 있다는 가정 하에 동작 + Canvas[] canvases = FindObjectsByType(FindObjectsSortMode.InstanceID); + foreach (Canvas c in canvases) + { + if (c.isRootCanvas) + { + rootCanvas = c; + break; + } + } + if (rootCanvas == null && canvases.Length > 0) rootCanvas = canvases[0]; // 최후의 수단 + } + } + + if (rootCanvas != null) + { + // defaultParent는 툴팁이 생성될 위치입니다. + // rootCanvas.transform을 사용하면 Canvas 직속 자식으로 생성됩니다. + // 또는 툴팁 전용 레이어를 두고 싶다면 해당 Transform을 사용합니다. + TooltipManager.Instance.Initialize(rootCanvas.transform, rootCanvas); + } + else + { + if (rootCanvas == null) Debug.LogError("ToolbarView: rootCanvas를 찾을 수 없어 TooltipVisualManager를 초기화할 수 없습니다."); } } - private void ClearToolbar() + public virtual void Initialize(ToolbarModel toolbarModel) + { + ToolbarModel = toolbarModel; + + if (toolbarContainer == null) + { + Debug.LogError("toolbarContainer가 할당되지 않았습니다."); + return; + } + + if (layoutGroup == null) + { + Debug.LogError("layoutGroup이 할당되지 않았습니다."); + return; + } + + RenderToolbar(); + } + + protected virtual void ClearToolbar() { foreach (var pair in _modelToGameObjectMap) { @@ -75,10 +131,10 @@ namespace UVC.UI.ToolBar _modelToGameObjectMap.Clear(); _toggleGroups.Clear(); // 토글 그룹도 정리 if (currentSubMenu != null) Destroy(currentSubMenu); - HideTooltip(); // 툴바가 클리어될 때 툴팁도 숨김 + TooltipManager.Instance.HideTooltip(); // 툴바가 클리어될 때 툴팁도 숨김 } - private void RenderToolbar() + protected void RenderToolbar() { ClearToolbar(); // 기존 UI 및 이벤트 구독 정리 @@ -114,117 +170,40 @@ namespace UVC.UI.ToolBar TooltipHandler tooltipHandler = itemObj.GetComponent(); if (tooltipHandler == null) tooltipHandler = itemObj.AddComponent(); - tooltipHandler.TooltipKey = buttonModel.TooltipKey; - tooltipHandler.OnPointerEnterAction = HandlePointerEnter; - tooltipHandler.OnPointerExitAction = HandlePointerExit; + tooltipHandler.Tooltip = buttonModel.TooltipKey; + tooltipHandler.OnPointerEnterAction = TooltipManager.Instance.HandlePointerEnter; + tooltipHandler.OnPointerExitAction = TooltipManager.Instance.HandlePointerExit; } } } } - } - private void HandlePointerEnter(string tooltipKey, Vector3 mousePosition) - { - if (LocalizationManager.Instance != null && _tooltipTextElement != null) + // 모든 항목이 추가된 후 toolbarContainer의 높이를 layoutGroup의 내용에 맞게 조절합니다. + if (layoutGroup != null) { - string tooltipText = LocalizationManager.Instance.GetString(tooltipKey); - if (string.IsNullOrEmpty(tooltipText) || tooltipText == $"[{tooltipKey}]") // 번역 실패 또는 키 그대로 반환 시 + // layoutGroup 컴포넌트가 있는 RectTransform을 가져옵니다. + // 일반적으로 toolbarContainer의 RectTransform과 동일합니다. + RectTransform layoutRectTransform = layoutGroup.GetComponent(); + if (layoutRectTransform != null) { - // 번역이 없거나 실패한 경우 툴팁을 표시하지 않거나, 기본 메시지를 표시할 수 있습니다. - // 여기서는 표시하지 않도록 합니다. - HideTooltip(); - return; + // 레이아웃을 즉시 재계산하도록 강제합니다. + // 이렇게 하면 preferredHeight가 현재 자식들을 기준으로 정확하게 계산됩니다. + LayoutRebuilder.ForceRebuildLayoutImmediate(layoutRectTransform); + + // LayoutGroup에 의해 계산된 선호 높이를 가져옵니다. + float preferredHeight = LayoutUtility.GetPreferredHeight(layoutRectTransform); + + // toolbarContainer (즉, layoutRectTransform)의 높이를 설정합니다. + // 이 코드는 toolbarContainer의 높이가 sizeDelta.y에 의해 제어된다고 가정합니다. + // 앵커가 수직으로 늘어나도록 설정된 경우, 이 방식이 원하는 대로 작동하지 않거나 + // anchoredPosition 및 오프셋을 대신 조정해야 할 수 있습니다. + layoutRectTransform.sizeDelta = new Vector2(layoutRectTransform.sizeDelta.x, preferredHeight); } - ShowTooltip(tooltipText, mousePosition); - } - } - - private void HandlePointerExit() - { - HideTooltip(); - } - - private void ShowTooltip(string text, Vector3 mousePosition) - { - if (_activeTooltipInstance == null || _tooltipTextElement == null) return; - - _tooltipTextElement.text = text; - _activeTooltipInstance.SetActive(true); - - // 툴팁 위치 설정 (마우스 커서 기준, 화면 가장자리 넘어가지 않도록 조정 필요) - // Canvas Render Mode에 따라 위치 계산 방식이 달라질 수 있습니다. - // Screen Space - Overlay 예시: - if (_tooltipRectTransform != null) - { - // TextMeshPro의 preferredWidth/Height를 사용하여 크기 조절 - _tooltipTextElement.ForceMeshUpdate(); // 텍스트 변경 후 메시 업데이트 강제 - Vector2 textSize = _tooltipTextElement.GetRenderedValues(false); - Vector2 padding = new Vector2(10, 5); // 툴팁 내부 여백 - _tooltipRectTransform.sizeDelta = textSize + padding * 2; - - - // 화면 가장자리 처리 (간단한 예시) - Vector2 localPoint; - RectTransformUtility.ScreenPointToLocalPointInRectangle( - transform.root as RectTransform, // Canvas의 최상위 RectTransform - mousePosition, - transform.root.GetComponent().worldCamera, // Screen Space - Camera 경우 필요 - out localPoint - ); - - // 툴팁을 마우스 오른쪽 아래에 표시 (오프셋 조정 가능) - _tooltipRectTransform.localPosition = localPoint + new Vector2(_tooltipRectTransform.sizeDelta.x * 0.5f + 10f, -_tooltipRectTransform.sizeDelta.y * 0.5f - 5f); - - - // 화면 경계 체크 및 위치 조정 (더 정교한 로직 필요) - Vector3[] corners = new Vector3[4]; - _tooltipRectTransform.GetWorldCorners(corners); - float screenWidth = Screen.width; - float screenHeight = Screen.height; - - // 오른쪽 경계 넘어감 - if (corners[2].x > screenWidth) - { - Vector3 currentPos = _tooltipRectTransform.position; - currentPos.x -= (corners[2].x - screenWidth); - _tooltipRectTransform.position = currentPos; - } - // 왼쪽 경계 넘어감 - if (corners[0].x < 0) - { - Vector3 currentPos = _tooltipRectTransform.position; - currentPos.x -= corners[0].x; - _tooltipRectTransform.position = currentPos; - } - // 아래쪽 경계 넘어감 (툴팁을 위로 표시하도록 변경 가능) - if (corners[0].y < 0) - { - Vector3 currentPos = _tooltipRectTransform.position; - currentPos.y -= corners[0].y; // 위로 올림 - // 또는 마우스 위쪽으로 위치 변경 - // _tooltipRectTransform.localPosition = localPoint + new Vector2(_tooltipRectTransform.sizeDelta.x * 0.5f + 10f, _tooltipRectTransform.sizeDelta.y * 0.5f + 5f); - _tooltipRectTransform.position = currentPos; - } - // 위쪽 경계 넘어감 - if (corners[1].y > screenHeight) - { - Vector3 currentPos = _tooltipRectTransform.position; - currentPos.y -= (corners[1].y - screenHeight); - _tooltipRectTransform.position = currentPos; - } - } - } - - private void HideTooltip() - { - if (_activeTooltipInstance != null) - { - _activeTooltipInstance.SetActive(false); } } // 버튼 모델과 게임 오브젝트를 받아 초기 시각적 요소 설정 및 UI 상호작용을 연결합니다. - private void SetupButtonVisualsAndInteractions(ToolbarButtonBase model, GameObject itemObj) + protected void SetupButtonVisualsAndInteractions(ToolbarButtonBase model, GameObject itemObj) { // 공통 UI 요소 업데이트 (Text, Icon, Enabled) UpdateCommonButtonVisuals(model, itemObj); @@ -242,7 +221,7 @@ namespace UVC.UI.ToolBar { // UI에서 사용자가 직접 토글한 경우 모델 업데이트 // 중요: 라디오 버튼은 그룹에 의해 선택이 관리되므로, isSelected가 true일 때만 모델 업데이트 요청 - if (isSelected) radioModel.ExecuteClick(); // 모델의 ExecuteClick -> RadioGroup.SetSelected 호출 + if (isSelected) radioModel.ExecuteClick(true); // 모델의 ExecuteClick -> RadioGroup.SetSelected 호출 }); // IsSelected 변경은 OnStateChanged를 통해 UpdateItemVisuals에서 처리되거나, // 좀 더 명시적인 OnToggleStateChanged 이벤트를 사용할 수 있습니다. @@ -281,14 +260,14 @@ namespace UVC.UI.ToolBar { uiButton.onClick.AddListener(() => { - standardModel.ExecuteClick(); + standardModel.ExecuteClick(standardModel.Text); }); } } } // 모델의 상태가 변경되었을 때 호출되어 모든 관련 UI를 업데이트합니다. - private void UpdateItemVisuals(ToolbarButtonBase model) + protected void UpdateItemVisuals(ToolbarButtonBase model) { if (_modelToGameObjectMap.TryGetValue(model, out GameObject itemObj)) { @@ -308,7 +287,7 @@ namespace UVC.UI.ToolBar } // 특정 토글 버튼/라디오 버튼의 IsSelected 상태가 모델에서 변경되었을 때 호출됩니다. - private void UpdateToggleVisuals(ToolbarToggleButton model, bool isSelected) + protected void UpdateToggleVisuals(ToolbarToggleButton model, bool isSelected) { if (_modelToGameObjectMap.TryGetValue(model, out GameObject itemObj)) { @@ -322,7 +301,7 @@ namespace UVC.UI.ToolBar // 공통 버튼 시각적 요소(텍스트, 아이콘, 활성화 상태)를 업데이트합니다. - private void UpdateCommonButtonVisuals(ToolbarButtonBase model, GameObject itemObj) + protected void UpdateCommonButtonVisuals(ToolbarButtonBase model, GameObject itemObj) { // 프리팹 구조에 대한 가정: // - 텍스트는 TextMeshProUGUI 컴포넌트를 가진 자식 오브젝트에 표시됩니다. @@ -344,19 +323,51 @@ namespace UVC.UI.ToolBar } } - Transform iconTransform = itemObj.transform.Find("Icon"); // 프리팹에 "Icon" 자식 오브젝트가 있다고 가정 - if (iconTransform != null) + Image buttonIcon = itemObj.GetComponent(); + + if (buttonIcon != null) { - Image buttonIcon = iconTransform.GetComponent(); + // Toggle이 있는 경우, 아이콘의 활성화 상태를 토글의 선택 상태에 따라 변경 + if (model is ToolbarToggleButton toolbarToggleButton) + { + buttonIcon.sprite = LoadSpriteFromResources(toolbarToggleButton.IsSelected ? toolbarToggleButton.IconSpritePath : toolbarToggleButton.OffIconSpritePath); + } + else if (model is ToolbarRadioButton radioButtonModel) + { + // 라디오 버튼의 아이콘은 선택 상태에 따라 다르게 설정할 수 있습니다. + buttonIcon.sprite = LoadSpriteFromResources(radioButtonModel.IsSelected ? model.IconSpritePath : radioButtonModel.OffIconSpritePath); + } + else + { + buttonIcon.sprite = LoadSpriteFromResources(model.IconSpritePath); + } + buttonIcon.gameObject.SetActive(model.IconSpritePath != null); + } + else + { + buttonIcon = itemObj.GetComponentInChildren(); if (buttonIcon != null) { - buttonIcon.sprite = model.Icon; - buttonIcon.gameObject.SetActive(model.Icon != null); + // Toggle이 있는 경우, 아이콘의 활성화 상태를 토글의 선택 상태에 따라 변경 + if (model is ToolbarToggleButton toolbarToggleButton) + { + buttonIcon.sprite = LoadSpriteFromResources(toolbarToggleButton.IsSelected ? toolbarToggleButton.IconSpritePath : toolbarToggleButton.OffIconSpritePath); + } + else if (model is ToolbarRadioButton radioButtonModel) + { + // 라디오 버튼의 아이콘은 선택 상태에 따라 다르게 설정할 수 있습니다. + buttonIcon.sprite = LoadSpriteFromResources(radioButtonModel.IsSelected ? model.IconSpritePath : radioButtonModel.OffIconSpritePath); + } + else + { + buttonIcon.sprite = LoadSpriteFromResources(model.IconSpritePath); + } + buttonIcon.gameObject.SetActive(model.IconSpritePath != null); } } - // 상호작용 가능 상태 업데이트 - Selectable selectable = itemObj.GetComponent(); // Button, Toggle 등 + // 상호작용 가능 상태 업데이트 + Selectable selectable = itemObj.GetComponent(); // Button, Toggle 등 if (selectable != null) { selectable.interactable = model.IsEnabled; @@ -364,13 +375,15 @@ namespace UVC.UI.ToolBar } - private Dictionary _toggleGroups = new Dictionary(); - private ToggleGroup GetOrCreateToggleGroup(string groupName) + protected Dictionary _toggleGroups = new Dictionary(); + protected ToggleGroup GetOrCreateToggleGroup(string groupName) { if (!_toggleGroups.TryGetValue(groupName, out ToggleGroup group)) { GameObject groupObj = new GameObject($"ToggleGroup_{groupName}"); groupObj.transform.SetParent(toolbarContainer); + RectTransform groupRect = groupObj.AddComponent(); + groupRect.sizeDelta = new Vector2(0, 0); // 크기는 필요에 따라 조정 group = groupObj.AddComponent(); group.allowSwitchOff = false; // 라디오 버튼 그룹은 일반적으로 하나는 선택되어 있도록 함 _toggleGroups.Add(groupName, group); @@ -378,9 +391,9 @@ namespace UVC.UI.ToolBar return group; } - private GameObject currentSubMenu = null; + protected GameObject currentSubMenu = null; // expandableButtonObj는 확장 메뉴의 위치를 잡기 위해 사용될 수 있습니다. - private void ToggleSubMenu(ToolbarExpandableButton expandableButton, GameObject expandableButtonObj) + protected void ToggleSubMenu(ToolbarExpandableButton expandableButton, GameObject expandableButtonObj) { if (currentSubMenu != null) { @@ -392,8 +405,9 @@ namespace UVC.UI.ToolBar if (subMenuPanelPrefab == null || expandableButton.SubButtons.Count == 0) return; currentSubMenu = Instantiate(subMenuPanelPrefab, transform); // ToolbarView의 자식으로 생성 후 위치 조정 - // 위치 조정 로직: expandableButtonObj의 위치를 기준으로 currentSubMenu의 RectTransform을 조정합니다. - // 예: currentSubMenu.transform.position = expandableButtonObj.transform.position + offset; + // 위치 조정 로직: expandableButtonObj의 위치를 기준으로 currentSubMenu의 RectTransform을 조정합니다. + Vector3 offset = new Vector3(expandableButtonObj.GetComponent().rect.width, 0, 0); + currentSubMenu.transform.position = expandableButtonObj.transform.position + offset; RectTransform panelRect = currentSubMenu.GetComponent(); // 하위 메뉴 패널에 LayoutGroup이 있다면 자식 버튼들이 자동으로 정렬됩니다. @@ -415,8 +429,11 @@ namespace UVC.UI.ToolBar subUiButton.interactable = subItem.IsEnabled; // 상호작용 상태 설정 subUiButton.onClick.AddListener(() => { - expandableButton.SelectSubButton(subItem); // 모델 업데이트 및 주 버튼 외형 변경 요청 + //expandableButton.SelectSubButton(subItem); // 모델 업데이트 및 주 버튼 외형 변경 요청 // 주 버튼 UI는 expandableButton의 OnStateChanged 이벤트에 의해 자동으로 업데이트됩니다. + subItem.ExecuteClick(subItem.Text); // 하위 버튼의 Command 실행 + expandableButton.OnSubButtonSelected?.Invoke(subItem); // 주 버튼에 하위 버튼 선택 알림 + Destroy(currentSubMenu); currentSubMenu = null; }); @@ -428,9 +445,9 @@ namespace UVC.UI.ToolBar TooltipHandler tooltipHandler = subButtonObj.GetComponent(); if (tooltipHandler == null) tooltipHandler = subButtonObj.AddComponent(); - tooltipHandler.TooltipKey = subItem.TooltipKey; - tooltipHandler.OnPointerEnterAction = HandlePointerEnter; - tooltipHandler.OnPointerExitAction = HandlePointerExit; + tooltipHandler.Tooltip = subItem.TooltipKey; + tooltipHandler.OnPointerEnterAction = TooltipManager.Instance.HandlePointerEnter; + tooltipHandler.OnPointerExitAction = TooltipManager.Instance.HandlePointerExit; } // 하위 버튼 모델의 OnStateChanged도 구독하여 하위 버튼 자체의 상태 변경(예: 텍스트)도 반영할 수 있습니다. @@ -440,14 +457,33 @@ namespace UVC.UI.ToolBar } } - void OnDestroy() + /// + /// 지정된 경로에서 Sprite를 로드합니다. Sprite 파일은 Resources 폴더 또는 그 하위 폴더에 있어야 합니다. + /// + /// Resources 폴더 기준의 Sprite 경로입니다 (확장자 제외). + /// 로드된 Sprite 객체. 실패 시 null을 반환합니다. + protected Sprite LoadSpriteFromResources(string spritePath) + { + if (string.IsNullOrEmpty(spritePath)) + { + Debug.LogWarning("LoadSpriteFromResources: spritePath가 null이거나 비어있습니다."); + return null; + } + Sprite loadedSprite = Resources.Load(spritePath); + if (loadedSprite == null) + { + Debug.LogError($"LoadSpriteFromResources: Resources 폴더에서 '{spritePath}' 경로의 Sprite를 로드할 수 없습니다."); + } + return loadedSprite; + } + + + + protected virtual void OnDestroy() { // 씬 전환 등으로 ToolbarView가 파괴될 때 모든 이벤트 구독 해제 ClearToolbar(); - if (_activeTooltipInstance != null) - { - Destroy(_activeTooltipInstance); // 툴팁 인스턴스도 파괴 - } + TooltipManager.Instance.Dispose(); // 툴팁 인스턴스도 파괴 } } } diff --git a/Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs b/Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs new file mode 100644 index 00000000..bddb82f8 --- /dev/null +++ b/Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs @@ -0,0 +1,171 @@ +using UnityEngine; +using UVC.Locale; +using UVC.UI.Commands; + +namespace UVC.UI.Toolbar +{ + public class ToolbarController : MonoBehaviour + { + protected ToolbarModel mainToolbar; + protected ToolbarView mainToolbarView; + + + protected virtual void Awake() + { + // 1. 이 GameObject에 연결된 ToolbarView 컴포넌트를 찾습니다. + mainToolbarView = GetComponent(); + + // 2. 만약 현재 GameObject에 없다면, 자식 GameObject들 중에서 ToolbarView 컴포넌트를 찾습니다. + if (mainToolbarView == null) + { + mainToolbarView = GetComponentInChildren(); + } + + } + + protected virtual void Start() + { + mainToolbar = new ToolbarModel(); + + // ToolbarView에 프리팹 설정은 ToolbarView 내부에서 처리하거나 Inspector에서 직접 할당합니다. + if (mainToolbarView == null) + { + Debug.LogError("ToolbarView가 할당되지 않았습니다."); + return; + } + + // --- 툴바 모델 구성 --- + + // 요청하신 기능으로 툴바 구성 + // 1. 카메라 조절 (RadioButtonGroup) + mainToolbar.AddRadioButton("CameraControlGroup", "Top View", true, + "Prefabs/UI/Toolbar/images/ic_camera_top_on", + "Prefabs/UI/Toolbar/images/ic_camera_top_off", + (isSelected) => { if (isSelected) Debug.Log("탑뷰 카메라 선택됨"); }, + new ActionCommand(() => Debug.Log("탑뷰 카메라 Command 실행")), + "Top View 시점으로 변경합니다."); + mainToolbar.AddRadioButton("CameraControlGroup", "Quarter View", false, + "Prefabs/UI/Toolbar/images/ic_camera_quarter_on", + "Prefabs/UI/Toolbar/images/ic_camera_quarter_off", + (isSelected) => { if (isSelected) Debug.Log("쿼터뷰 카메라 선택됨"); }, + new ActionCommand(() => Debug.Log("쿼터뷰 카메라 Command 실행")), + "Quarter View 시점으로 변경합니다."); + mainToolbar.AddRadioButton("CameraControlGroup", "Front View", false, + "Prefabs/UI/Toolbar/images/ic_camera_top_on", + "Prefabs/UI/Toolbar/images/ic_camera_top_off", + (isSelected) => { if (isSelected) Debug.Log("프런트뷰 카메라 선택됨"); }, + new ActionCommand(() => Debug.Log("프런트뷰 카메라 Command 실행")), + "Front View 시점으로 변경합니다."); + + // 2. 구분선 + mainToolbar.AddSeparator(); + + // 3. 객체 선택 + mainToolbar.AddStandardButton("선택", + "Prefabs/UI/Toolbar/images/ic_select", + new ActionCommand(() => Debug.Log("객체 선택 버튼 클릭됨")), + "객체를 선택합니다."); + + // 4. 객체 이동 + mainToolbar.AddStandardButton("이동", + "Prefabs/UI/Toolbar/images/ic_move", + new ActionCommand(() => Debug.Log("객체 이동 버튼 클릭됨")), + "객체를 이동 시킵니다."); + + // 5. 객체 회전 + mainToolbar.AddStandardButton("회전", + "Prefabs/UI/Toolbar/images/ic_rotation", + new ActionCommand(() => Debug.Log("객체 회전 버튼 클릭됨")), + "객체의 각도를 조절합니다."); + + // 6. 객체 크기조절 + mainToolbar.AddStandardButton("크기조절", + "Prefabs/UI/Toolbar/images/ic_scale", + new ActionCommand(() => Debug.Log("객체 크기조절 버튼 클릭됨")), + "객체 크기를 조절합니다."); + + // 7. 객체 복제 + mainToolbar.AddStandardButton("복제", + "Prefabs/UI/Toolbar/images/ic_copy", + new ActionCommand(() => Debug.Log("객체 복제 버튼 클릭됨")), + "객체를 복제 합니다."); + + // 8. 객체 삭제 + mainToolbar.AddStandardButton("삭제", + "Prefabs/UI/Toolbar/images/ic_delete", + new ActionCommand(() => Debug.Log("객체 삭제 버튼 클릭됨")), + "객체를 삭제 합니다."); + + mainToolbar.AddSeparator(); + + // 9. 화면 캡처 + mainToolbar.AddStandardButton("button_capture_screen", + "Prefabs/UI/Toolbar/images/ic_chapture", + new ActionCommand(() => Debug.Log("화면 캡처 버튼 클릭됨")), + "tooltip_capture_screen"); + + // 10. 화면 녹화 시작/중지 (ToggleButton) + mainToolbar.AddToggleButton("button_record_screen", false, + "Prefabs/UI/Toolbar/images/ic_record_on", + "Prefabs/UI/Toolbar/images/ic_record_off", + (isSelected) => Debug.Log($"화면 녹화 상태: {(isSelected ? "녹화 중" : "중지")} (OnToggle 콜백)"), + new ActionCommand((isRecording) => Debug.Log($"화면 녹화 Command 실행: {(isRecording ? "녹화 시작" : "녹화 중지")}")), + "tooltip_record_screen"); + + + // 기존 확장 버튼 (예시로 남겨두거나 필요에 따라 수정/제거) + var expandableBtnModel = mainToolbar.AddExpandableButton("button_brush_size", + "Prefabs/UI/Toolbar/images/ic_brush_default", + new ActionCommand(() => Debug.Log("브러시 크기 주 버튼 클릭됨 (Command)")), + "붓 사이즈 선택 합니다."); + + var smallBrushCmd = new ActionCommand((size) => Debug.Log($"작은 브러시 ({size}) 선택됨"), 5.0f); + var smallBrush = new ToolbarStandardButton + { + Text = "brush_size_small", + IconSpritePath = "Prefabs/UI/Toolbar/images/ic_brush_small", + TooltipKey = "tooltip_brush_small", + ClickCommand = smallBrushCmd + }; + expandableBtnModel.SubButtons.Add(smallBrush); + + var mediumBrush = new ToolbarStandardButton + { + Text = "brush_size_medium", + IconSpritePath = "Prefabs/UI/Toolbar/images/ic_brush_medium", + TooltipKey = "tooltip_brush_medium", + ClickCommand = new ActionCommand(() => Debug.Log("중간 브러시 선택됨 (Sub-Command 실행)")) + }; + expandableBtnModel.SubButtons.Add(mediumBrush); + + expandableBtnModel.OnSubButtonSelected = (selectedSubButtonModel) => + { + string localizedSubButtonText = LocalizationManager.Instance != null ? LocalizationManager.Instance.GetString(selectedSubButtonModel.Text) : selectedSubButtonModel.Text; + Debug.Log($"브러시 크기 '{localizedSubButtonText}' 선택됨 (OnSubButtonSelected 콜백). 주 버튼 업데이트 로직 실행 가능."); + }; + // --- 툴바 모델 구성 끝 --- + + + // ToolbarView 초기화 및 렌더링 + mainToolbarView.Initialize(mainToolbar); + + + // 예시: 모델 상태를 코드로 변경하고 UI가 업데이트되는지 테스트 + // StartCoroutine(TestModelChange(saveBtnModel, muteToggleModel)); + } + + + + // System.Collections.IEnumerator TestModelChange(ToolbarStandardButton standard, ToolbarToggleButton toggle) + // { + // yield return new WaitForSeconds(2f); + // Debug.Log("모델 변경 테스트: 저장 버튼 비활성화 및 텍스트 변경"); + // standard.Text = "저장됨"; + // standard.IsEnabled = false; + // + // yield return new WaitForSeconds(2f); + // Debug.Log("모델 변경 테스트: 음소거 토글 상태 변경"); + // toggle.IsSelected = true; + // } + } +} diff --git a/Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs.meta b/Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs.meta similarity index 100% rename from Assets/Scripts/UVC/UI/ToolBar/ToolbarManager.cs.meta rename to Assets/Scripts/UVC/UI/Toolbar/ToolbarController.cs.meta diff --git a/Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs b/Assets/Scripts/UVC/UI/Toolbar/ToolbarModel.cs similarity index 70% rename from Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs rename to Assets/Scripts/UVC/UI/Toolbar/ToolbarModel.cs index d2ca2773..c8d90ae3 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs +++ b/Assets/Scripts/UVC/UI/Toolbar/ToolbarModel.cs @@ -1,15 +1,18 @@ -namespace UVC.UI.ToolBar +using UnityEngine; +using UVC.UI.Commands; + +namespace UVC.UI.Toolbar { /// /// 툴바의 전체적인 컨테이너 및 관리 클래스입니다. /// IToolbarItem 객체들을 동적으로 추가하고 관리합니다. /// - public class Toolbar + public class ToolbarModel { public System.Collections.Generic.List Items { get; private set; } private System.Collections.Generic.Dictionary _radioGroups; - public Toolbar() + public ToolbarModel() { Items = new System.Collections.Generic.List(); _radioGroups = new System.Collections.Generic.Dictionary(); @@ -31,23 +34,23 @@ // UI 갱신 로직 호출 } - public ToolbarStandardButton AddStandardButton(string text, UnityEngine.Sprite icon = null, System.Action onClick = null, string tooltipKey = null) + public ToolbarStandardButton AddStandardButton(string text, string iconSpritePath = null, ICommand command = null, string tooltipKey = null) { - var button = new ToolbarStandardButton { Text = text, Icon = icon, OnClick = onClick, TooltipKey = tooltipKey }; + var button = new ToolbarStandardButton { Text = text, IconSpritePath = iconSpritePath, ClickCommand = command, TooltipKey = tooltipKey }; AddItem(button); return button; } - public ToolbarToggleButton AddToggleButton(string text, bool initialState = false, UnityEngine.Sprite icon = null, System.Action onToggle = null, string tooltipKey = null) + public ToolbarToggleButton AddToggleButton(string text, bool initialState = false, string onIconSpritePath = null, string offIconSpritePath = null, System.Action onToggle = null, ICommand command = null, string tooltipKey = null) { - var button = new ToolbarToggleButton { Text = text, IsSelected = initialState, Icon = icon, OnToggle = onToggle, TooltipKey = tooltipKey }; + var button = new ToolbarToggleButton { Text = text, IsSelected = initialState, IconSpritePath = onIconSpritePath, OffIconSpritePath = offIconSpritePath, OnToggle = onToggle, ClickCommand = command, TooltipKey = tooltipKey }; AddItem(button); return button; } - public ToolbarRadioButton AddRadioButton(string groupName, string text, bool initialState = false, UnityEngine.Sprite icon = null, System.Action onToggle = null, string tooltipKey = null) + public ToolbarRadioButton AddRadioButton(string groupName, string text, bool initialState = false, string iconSpritePath = null, string offIconSpritePath = null, System.Action onToggle = null, ICommand command = null, string tooltipKey = null) { - var button = new ToolbarRadioButton(groupName) { Text = text, IsSelected = initialState, Icon = icon, OnToggle = onToggle, TooltipKey = tooltipKey }; + var button = new ToolbarRadioButton(groupName) { Text = text, IsSelected = initialState, IconSpritePath = iconSpritePath, OffIconSpritePath = offIconSpritePath, OnToggle = onToggle, ClickCommand = command, TooltipKey = tooltipKey }; // AddItem 내에서 그룹 처리가 되므로, 여기서는 IsSelected 초기값만 주의 (그룹 내 하나만 true여야 함) AddItem(button); // 그룹의 초기 선택 상태를 설정하는 로직이 추가로 필요할 수 있습니다. @@ -59,9 +62,9 @@ return button; } - public ToolbarExpandableButton AddExpandableButton(string text, UnityEngine.Sprite icon = null, System.Action onClick = null, string tooltipKey = null) + public ToolbarExpandableButton AddExpandableButton(string text, string iconSpritePath = null, ICommand command = null, string tooltipKey = null) { - var button = new ToolbarExpandableButton { Text = text, Icon = icon, OnClick = onClick, TooltipKey = tooltipKey }; + var button = new ToolbarExpandableButton { Text = text, IconSpritePath = iconSpritePath, ClickCommand = command, TooltipKey = tooltipKey }; AddItem(button); return button; } diff --git a/Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs.meta b/Assets/Scripts/UVC/UI/Toolbar/ToolbarModel.cs.meta similarity index 100% rename from Assets/Scripts/UVC/UI/ToolBar/Toolbar.cs.meta rename to Assets/Scripts/UVC/UI/Toolbar/ToolbarModel.cs.meta diff --git a/Assets/Scripts/UVC/UI/Tooltip.meta b/Assets/Scripts/UVC/UI/Tooltip.meta new file mode 100644 index 00000000..1cc6dd7e --- /dev/null +++ b/Assets/Scripts/UVC/UI/Tooltip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7423e86407a2a72418bf784190acd2b2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs b/Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs similarity index 65% rename from Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs rename to Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs index 92845dc5..abdfc695 100644 --- a/Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs +++ b/Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs @@ -2,19 +2,19 @@ using UnityEngine.EventSystems; using UnityEngine.UI; -namespace UVC.UI.ToolBar +namespace UVC.UI.Tooltip { public class TooltipHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { public System.Action OnPointerEnterAction; // 툴팁 내용(키), 마우스 위치 public System.Action OnPointerExitAction; - public string TooltipKey { get; set; } + public string Tooltip { get; set; } public void OnPointerEnter(PointerEventData eventData) { - if (!string.IsNullOrEmpty(TooltipKey) && gameObject.GetComponent()?.interactable == true) // 버튼이 활성화 상태일 때만 + if (!string.IsNullOrEmpty(Tooltip) && gameObject.GetComponent()?.interactable == true) // 버튼이 활성화 상태일 때만 { - OnPointerEnterAction?.Invoke(TooltipKey, Input.mousePosition); + OnPointerEnterAction?.Invoke(Tooltip, Input.mousePosition); } } diff --git a/Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs.meta b/Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs.meta similarity index 100% rename from Assets/Scripts/UVC/UI/ToolBar/TooltipHandler.cs.meta rename to Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs.meta diff --git a/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs b/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs new file mode 100644 index 00000000..6baf359e --- /dev/null +++ b/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs @@ -0,0 +1,276 @@ +using TMPro; +using UnityEngine; +using UVC.Locale; // LocalizationManager를 사용한다면 필요합니다. + +namespace UVC.UI.Tooltip +{ + public class TooltipManager + { + + #region Singleton Implementation + private static TooltipManager _instance; + public static TooltipManager Instance + { + get + { + if (_instance == null) + { + _instance = new TooltipManager(); + } + return _instance; + } + } + // 외부에서 직접 생성하지 못하도록 protected 생성자로 변경 + protected TooltipManager() { } + #endregion + + protected Transform _defaultParentTransform; // 툴팁 인스턴스가 생성될 기본 부모 Transform + protected Canvas _rootCanvas; // 화면 좌표 계산 및 UI 스케일링에 사용될 Canvas + + protected GameObject _activeTooltipInstance; + protected TextMeshProUGUI _tooltipTextElement; + protected RectTransform _tooltipRectTransform; + + protected bool _isInitialized = false; + + protected string tooltipPrefabPath = "Prefabs/UI/Tooltip/Tooltip"; + protected virtual string TooltipPrefabPath => tooltipPrefabPath; + + /// + /// TooltipVisualManager를 초기화합니다. 이 메서드는 한 번만 호출되어야 합니다. + /// 일반적으로 애플리케이션 시작 시점이나 UI 시스템이 로드될 때 호출됩니다. + /// + /// 생성된 툴팁 인스턴스의 기본 부모 Transform입니다. 보통 Canvas의 Transform입니다. + /// 툴팁의 위치와 크기를 계산하는 데 사용될 최상위 Canvas입니다. + /// Resources 폴더 내의 툴팁 UI 프리팹 경로입니다. + public void Initialize(Transform defaultParent, Canvas rootCanvas, string tooltipPrefabPath = null) + { + if (_isInitialized) + { + Debug.LogWarning("TooltipVisualManager는 이미 초기화되었습니다."); + return; + } + + if (defaultParent == null) + { + Debug.LogError("TooltipVisualManager 초기화 실패: defaultParent가 null입니다."); + return; + } + if (rootCanvas == null) + { + Debug.LogError("TooltipVisualManager 초기화 실패: rootCanvas가 null입니다."); + return; + } + + if (!string.IsNullOrEmpty(tooltipPrefabPath)) + { + this.tooltipPrefabPath = tooltipPrefabPath; // 사용자 지정 경로가 제공되면 업데이트 + } + + GameObject loadedTooltipPrefab = Resources.Load(this.tooltipPrefabPath); + + if (loadedTooltipPrefab == null) + { + Debug.LogError($"TooltipManager 초기화 실패: Resources 폴더에서 '{this.tooltipPrefabPath}' 경로의 프리팹을 로드할 수 없습니다."); + return; + } + + _defaultParentTransform = defaultParent; + _rootCanvas = rootCanvas; + + // 툴팁 인스턴스 생성 및 초기화 + _activeTooltipInstance = GameObject.Instantiate(loadedTooltipPrefab, _defaultParentTransform); + _tooltipTextElement = _activeTooltipInstance.GetComponentInChildren(); + _tooltipRectTransform = _activeTooltipInstance.GetComponent(); + + if (_tooltipTextElement == null || _tooltipRectTransform == null) + { + Debug.LogError("TooltipVisualManager 초기화 실패: tooltipPrefab의 구성요소가 올바르지 않습니다. TextMeshProUGUI와 RectTransform이 필요합니다."); + if (_activeTooltipInstance != null) GameObject.Destroy(_activeTooltipInstance); + _activeTooltipInstance = null; // 초기화 실패 상태로 설정 + return; + } + + _activeTooltipInstance.SetActive(false); // 처음에는 숨김 + _isInitialized = true; + // Debug.Log("TooltipVisualManager 초기화 완료."); + } + + public void HandlePointerEnter(string tooltip, Vector3 mousePosition) + { + if (!_isInitialized || _activeTooltipInstance == null) + { + // Debug.LogWarning("TooltipVisualManager가 초기화되지 않았거나 툴팁 인스턴스가 없습니다."); + return; + } + + string tooltipText = tooltip; // 기본값은 키 자체 + if (LocalizationManager.Instance != null && !string.IsNullOrEmpty(tooltip)) + { + string localizedText = LocalizationManager.Instance.GetString(tooltip); + if (!string.IsNullOrEmpty(localizedText) && localizedText != tooltip) // 번역 성공 시 + { + tooltipText = localizedText; + } + else if (string.IsNullOrEmpty(localizedText)) // 번역 결과가 비어있으면 숨김 + { + HideTooltip(); + return; + } + } + + if (string.IsNullOrEmpty(tooltipText)) + { + HideTooltip(); + return; + } + ShowTooltip(tooltipText, mousePosition); + } + + public void HandlePointerExit() + { + if (!_isInitialized) return; + HideTooltip(); + } + + private void ShowTooltip(string text, Vector3 mousePosition) + { + if (_activeTooltipInstance == null || _tooltipTextElement == null || _tooltipRectTransform == null) return; + + _tooltipTextElement.text = text; + _activeTooltipInstance.SetActive(true); + + _tooltipTextElement.ForceMeshUpdate(); + Vector2 textSize = _tooltipTextElement.GetRenderedValues(false); + Vector2 padding = new Vector2(10, 2); // 툴팁 내부 여백 (값 증가) + _tooltipRectTransform.sizeDelta = textSize + padding * 2; + + AdjustPosition(mousePosition); + } + + private void AdjustPosition(Vector3 mousePosition) + { + if (_rootCanvas == null || _tooltipRectTransform == null) return; + + Vector2 localPoint; + Camera eventCamera = (_rootCanvas.renderMode == RenderMode.ScreenSpaceOverlay) ? null : _rootCanvas.worldCamera; + RectTransformUtility.ScreenPointToLocalPointInRectangle( + _rootCanvas.transform as RectTransform, + mousePosition, + eventCamera, + out localPoint + ); + + // 툴팁을 마우스 오른쪽 아래에 표시 (오프셋 조정) + // Pivot이 (0,1) (좌상단)이라고 가정하고 위치 조정 + Vector2 pivotOffset = new Vector2( + _tooltipRectTransform.sizeDelta.x * _tooltipRectTransform.pivot.x + 10f, + _tooltipRectTransform.sizeDelta.y * (1 - _tooltipRectTransform.pivot.y) + ); + + Debug.Log($"Tooltip Positioning: Local Point = {localPoint}, Pivot Offset = {pivotOffset}"); + + // 기본 위치: 마우스 포인터의 오른쪽 아래 + //Vector2 tooltipPosition = localPoint + new Vector2(0f, -0f - _tooltipRectTransform.sizeDelta.y); + + + // Pivot을 고려하여 최종 localPosition 설정 + // _tooltipRectTransform.localPosition = tooltipPosition; // Pivot (0.5, 0.5) 기준이라면 이렇게 간단할 수 있음 + // 현재는 Pivot에 따라 위치를 보정하는 코드가 복잡해질 수 있으므로, + // 툴팁 프리팹의 Pivot을 (0,1) (좌상단) 또는 (0.5, 0.5) (중앙) 등으로 통일하는 것을 권장합니다. + // 여기서는 간단히 localPoint를 기준으로 오프셋만 적용합니다. 실제 Pivot에 맞게 조정 필요. + _tooltipRectTransform.localPosition = localPoint + pivotOffset;// localPoint + new Vector2(15, -_tooltipRectTransform.sizeDelta.y - 15); + + + // 화면 경계 처리 + AdjustPositionWithinScreenBounds(); + } + + + public void HideTooltip() + { + if (_activeTooltipInstance != null) + { + _activeTooltipInstance.SetActive(false); + } + } + + private void AdjustPositionWithinScreenBounds() + { + if (_tooltipRectTransform == null || _activeTooltipInstance == null || !_activeTooltipInstance.activeSelf || _rootCanvas == null) return; + + Vector3[] tooltipCorners = new Vector3[4]; + _tooltipRectTransform.GetWorldCorners(tooltipCorners); // 툴팁의 월드 좌표 코너 + + RectTransform canvasRectTransform = _rootCanvas.transform as RectTransform; + Vector3[] canvasCorners = new Vector3[4]; + canvasRectTransform.GetWorldCorners(canvasCorners); // 캔버스의 월드 좌표 코너 (Screen Space Overlay에서는 화면 전체) + + // Screen Space Overlay에서는 Screen.width/height를 사용하는 것이 더 직관적일 수 있음 + float minX = 0; + float maxX = Screen.width; + float minY = 0; + float maxY = Screen.height; + + if (_rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay) + { + // Screen Space Camera 또는 World Space의 경우 캔버스 경계를 사용 + minX = canvasCorners[0].x; // Bottom-left X + maxX = canvasCorners[2].x; // Top-right X + minY = canvasCorners[0].y; // Bottom-left Y + maxY = canvasCorners[1].y; // Top-left Y (또는 corners[2].y) + } + + Vector3 currentPosition = _tooltipRectTransform.position; + Vector2 size = _tooltipRectTransform.sizeDelta * _rootCanvas.scaleFactor; // 실제 픽셀 크기 + Vector2 pivot = _tooltipRectTransform.pivot; + + // 오른쪽 경계 넘어감 + if (tooltipCorners[2].x > maxX) + { + currentPosition.x -= (tooltipCorners[2].x - maxX); + } + // 왼쪽 경계 넘어감 + if (tooltipCorners[0].x < minX) + { + currentPosition.x += (minX - tooltipCorners[0].x); + } + // 아래쪽 경계 넘어감 -> 위로 표시 (마우스 포인터 위쪽으로) + if (tooltipCorners[0].y < minY) + { + // 마우스 포인터의 월드 Y + 약간의 오프셋 + 툴팁 높이 (pivot 고려) + Vector3 mouseWorldPos = Vector3.zero; + if (_rootCanvas.renderMode == RenderMode.ScreenSpaceOverlay) mouseWorldPos = Input.mousePosition; + else RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, Input.mousePosition, _rootCanvas.worldCamera, out mouseWorldPos); + + currentPosition.y = mouseWorldPos.y + (size.y * (1 - pivot.y)) + 15f; // 15f는 오프셋 + } + // 위쪽 경계 넘어감 + if (tooltipCorners[1].y > maxY) // Top-left corner Y + { + currentPosition.y -= (tooltipCorners[1].y - maxY); + } + _tooltipRectTransform.position = currentPosition; + } + + /// + /// TooltipVisualManager가 사용하던 리소스를 해제합니다. + /// 애플리케이션 종료 시 또는 UI 시스템 해제 시 호출하는 것이 좋습니다. + /// + public void Dispose() + { + if (_activeTooltipInstance != null) + { + GameObject.Destroy(_activeTooltipInstance); + _activeTooltipInstance = null; + } + _tooltipTextElement = null; + _tooltipRectTransform = null; + _defaultParentTransform = null; + _rootCanvas = null; + _isInitialized = false; + _instance = null; // 싱글톤 인스턴스 참조 해제 + // Debug.Log("TooltipVisualManager Disposed."); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs.meta b/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs.meta new file mode 100644 index 00000000..2bd92640 --- /dev/null +++ b/Assets/Scripts/UVC/UI/Tooltip/TooltipManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fce7ae5b3ec11d541854b89ca1edaf6f \ No newline at end of file