├── Editor ├── Scripts.meta ├── Icons │ ├── ImuiUnityGUIBackend.psd │ └── ImuiUnityGUIBackend.psd.meta ├── Scripts │ ├── Imui.Editor.asmdef.meta │ ├── ImuiUnityGUIBackend.cs.meta │ ├── Imui.Editor.asmdef │ └── ImuiUnityGUIBackend.cs └── Icons.meta ├── Runtime ├── Scripts.meta ├── Resources │ ├── Imui.meta │ └── Imui │ │ ├── FiraMono-Regular.ttf │ │ ├── imui_ugui.shader.meta │ │ ├── imui_wireframe.shader.meta │ │ ├── imui_default.shader.meta │ │ ├── FiraMono-Regular.ttf.meta │ │ ├── imui_wireframe.shader │ │ ├── imui_default.shader │ │ └── imui_ugui.shader ├── Scripts │ ├── Core.meta │ ├── IO.meta │ ├── Style.meta │ ├── Controls.meta │ ├── Examples.meta │ ├── IO │ │ ├── Events.meta │ │ ├── Touch.meta │ │ ├── UGUI.meta │ │ ├── Utility.meta │ │ ├── IImuiInput.cs.meta │ │ ├── Rendering.meta │ │ ├── IImuiRenderer.cs.meta │ │ ├── Events │ │ │ ├── ImMouseEvent.cs.meta │ │ │ ├── ImTextEvent.cs.meta │ │ │ ├── ImKeyboardEvent.cs.meta │ │ │ ├── ImKeyboardEvent.cs │ │ │ ├── ImTextEvent.cs │ │ │ └── ImMouseEvent.cs │ │ ├── Touch │ │ │ ├── ImTouchKeyboard.cs.meta │ │ │ └── ImTouchKeyboard.cs │ │ ├── Utility │ │ │ ├── ImDynamicRenderTexture.cs.meta │ │ │ ├── ImUnityInputWrapper.cs.meta │ │ │ ├── ImUnityScrollUtility.cs.meta │ │ │ ├── ImKeyboardCommandsHelper.cs.meta │ │ │ ├── ImUnityScrollUtility.cs │ │ │ ├── ImUnityInputWrapper.cs │ │ │ ├── ImDynamicRenderTexture.cs │ │ │ └── ImKeyboardCommandsHelper.cs │ │ ├── Rendering │ │ │ ├── ImuiBuiltinRenderingScheduler.cs.meta │ │ │ ├── ImuiScriptableRenderingScheduler.cs.meta │ │ │ ├── ImuiBuiltinRenderingScheduler.cs │ │ │ └── ImuiScriptableRenderingScheduler.cs │ │ ├── UGUI │ │ │ └── ImuiUnityGUIBackend.cs.meta │ │ ├── IImuiRenderer.cs │ │ └── IImuiInput.cs │ ├── Utility.meta │ ├── Controls │ │ ├── Utility.meta │ │ ├── ImButton.cs.meta │ │ ├── ImFoldout.cs.meta │ │ ├── ImGrid.cs.meta │ │ ├── ImGroup.cs.meta │ │ ├── ImImage.cs.meta │ │ ├── ImList.cs.meta │ │ ├── ImMenu.cs.meta │ │ ├── ImMenuBar.cs.meta │ │ ├── ImPopup.cs.meta │ │ ├── ImScroll.cs.meta │ │ ├── ImSlider.cs.meta │ │ ├── ImTable.cs.meta │ │ ├── ImText.cs.meta │ │ ├── ImTooltip.cs.meta │ │ ├── ImTree.cs.meta │ │ ├── ImVector.cs.meta │ │ ├── ImWindow.cs.meta │ │ ├── ImCheckbox.cs.meta │ │ ├── ImColorButton.cs.meta │ │ ├── ImColorEdit.cs.meta │ │ ├── ImColorPicker.cs.meta │ │ ├── ImContextMenu.cs.meta │ │ ├── ImDropdown.cs.meta │ │ ├── ImNumericEdit.cs.meta │ │ ├── ImRadiobox.cs.meta │ │ ├── ImSeparator.cs.meta │ │ ├── ImTabsPane.cs.meta │ │ ├── ImTextEdit.cs.meta │ │ ├── Utility │ │ │ ├── ImSize.cs.meta │ │ │ ├── ImDrawingUtility.cs.meta │ │ │ ├── ImLayoutUtility.cs.meta │ │ │ ├── ImRectUtility.cs.meta │ │ │ ├── ImStyleScope.cs.meta │ │ │ ├── ImDrawingUtility.cs │ │ │ ├── ImSize.cs │ │ │ ├── ImStyleScope.cs │ │ │ └── ImLayoutUtility.cs │ │ ├── ImContextMenu.cs │ │ ├── ImTooltip.cs │ │ ├── ImPopup.cs │ │ ├── ImList.cs │ │ ├── ImSeparator.cs │ │ ├── ImGrid.cs │ │ ├── ImGroup.cs │ │ ├── ImFoldout.cs │ │ ├── ImColorEdit.cs │ │ ├── ImMenuBar.cs │ │ ├── ImCheckbox.cs │ │ ├── ImColorButton.cs │ │ ├── ImRadiobox.cs │ │ ├── ImImage.cs │ │ ├── ImTabsPane.cs │ │ ├── ImVector.cs │ │ └── ImText.cs │ ├── Core │ │ ├── ImAABB.cs.meta │ │ ├── ImAxis.cs.meta │ │ ├── ImCanvas.cs.meta │ │ ├── ImGui.cs.meta │ │ ├── ImHash.cs.meta │ │ ├── ImLayout.cs.meta │ │ ├── ImRect.cs.meta │ │ ├── ImShapes.cs.meta │ │ ├── ImFormatter.cs.meta │ │ ├── ImStorage.cs.meta │ │ ├── ImCanvas.Utility.cs.meta │ │ ├── ImTextSettings.cs.meta │ │ ├── ImWindowManager.cs.meta │ │ ├── ImAxis.cs │ │ ├── ImArena.cs.meta │ │ ├── ImTextSettings.cs │ │ ├── ImAABB.cs │ │ ├── ImHash.cs │ │ ├── ImWindowManager.cs │ │ └── ImFormatter.cs │ ├── Style │ │ ├── ImTheme.cs.meta │ │ ├── ImAlignment.cs.meta │ │ ├── ImPadding.cs.meta │ │ ├── ImStyleSheet.cs.meta │ │ ├── ImColorUtility.cs.meta │ │ ├── ImStyleControls.cs.meta │ │ ├── ImStyleSheetBuilder.cs.meta │ │ ├── ImColorHcl.cs.meta │ │ ├── ImAlignment.cs │ │ ├── ImColorUtility.cs │ │ ├── ImStyleSheet.cs │ │ ├── ImPadding.cs │ │ └── ImColorHcl.cs │ ├── Rendering │ │ ├── ImVertex.cs.meta │ │ ├── ImMeshBuffer.cs.meta │ │ ├── ImTextDrawer.cs.meta │ │ ├── ImMeshData.cs.meta │ │ ├── ImMeshDrawer.cs.meta │ │ ├── ImMeshRenderer.cs.meta │ │ ├── ImMeshData.cs │ │ ├── ImVertex.cs │ │ └── ImMeshBuffer.cs │ ├── Utility │ │ ├── ImAssert.cs.meta │ │ ├── ImProfiler.cs.meta │ │ ├── ImDynamicArray.cs.meta │ │ ├── ImEnumUtility.cs.meta │ │ ├── ImUnityUtility.cs.meta │ │ ├── ImCircularBuffer.cs.meta │ │ ├── ImUnityUtility.cs │ │ ├── ImProfiler.cs │ │ ├── ImAssert.cs │ │ ├── ImDynamicArray.cs │ │ └── ImCircularBuffer.cs │ ├── Examples │ │ ├── ImDebugWindow.cs.meta │ │ ├── ImDemoWindow.cs.meta │ │ ├── ImThemeEditor.cs.meta │ │ ├── ImConsoleWindow.cs.meta │ │ └── ImThemeEditor.cs │ ├── Imui.asmdef.meta │ ├── Rendering.meta │ └── Imui.asmdef └── Resources.meta ├── Samples~ ├── Scenes.meta ├── Scripts.meta ├── Scripts │ ├── DemoRoot.cs.meta │ ├── Imui.Demo.asmdef.meta │ ├── Imui.Demo.asmdef │ └── DemoRoot.cs └── Scenes │ └── Imui Demo Scene.unity.meta ├── LICENSE.md.meta ├── README.md.meta ├── package.json.meta ├── Editor.meta ├── Runtime.meta ├── package.json ├── LICENSE.md ├── README.md └── .gitignore /Editor/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1882700da7cf4155b5e475633792adde 3 | timeCreated: 1739225793 -------------------------------------------------------------------------------- /Runtime/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 28254d5170194fa6b2a0902f169d495d 3 | timeCreated: 1707425983 -------------------------------------------------------------------------------- /Samples~/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9314339f361141f887dc94c36238140 3 | timeCreated: 1717794329 -------------------------------------------------------------------------------- /Samples~/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e04d881f7db3c432a84c9cc1576417a0 3 | timeCreated: 1717794332 -------------------------------------------------------------------------------- /Editor/Icons/ImuiUnityGUIBackend.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vape/Imui/HEAD/Editor/Icons/ImuiUnityGUIBackend.psd -------------------------------------------------------------------------------- /Runtime/Resources/Imui.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a96af19311c4f97818c3f760f391a38 3 | timeCreated: 1739102327 -------------------------------------------------------------------------------- /Runtime/Scripts/Core.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd3a821d888b43caa5d72c066ab60e97 3 | timeCreated: 1707430462 -------------------------------------------------------------------------------- /Runtime/Scripts/IO.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 858d3d25b7184247af5cf8d9042ced43 3 | timeCreated: 1716072052 -------------------------------------------------------------------------------- /Runtime/Scripts/Style.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d389b088ee5146a990dbfd00bd7ef430 3 | timeCreated: 1728578815 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 920fb2af8c304ab498d22558dd67f949 3 | timeCreated: 1707684475 -------------------------------------------------------------------------------- /Runtime/Scripts/Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2563c9ee33d445d94eda41296bc1be5 3 | timeCreated: 1730934356 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5aa8b24be4bd4747ae8573c8d7aeebde 3 | timeCreated: 1716076657 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Touch.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 870825dcc14a4834a3e46f45ae2f61eb 3 | timeCreated: 1739304252 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/UGUI.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 053c4ff365594b4a9bc4271e1cb041ed 3 | timeCreated: 1716076867 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 65c94b452a8c4c1da2e6cdd46b2dd435 3 | timeCreated: 1716119409 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e4ce173d958d481e80abb3b301eba37f 3 | timeCreated: 1707426596 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9f15120e7ade45f181c42e5ed229bb61 3 | timeCreated: 1717541278 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImAABB.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 262b667d9fdb4fe4984ba297260514da 3 | timeCreated: 1738871136 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImAxis.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5400b5c130244b39b5517525288cf821 3 | timeCreated: 1708376605 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImCanvas.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a2ad97984ce4ae3bc4ecad7effcea8c 3 | timeCreated: 1707430539 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImGui.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38cc8d8658d344538b5b3e0e9833922f 3 | timeCreated: 1707432232 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImHash.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ba1295bfd6b247a3a3c5eba44fb0e5f9 3 | timeCreated: 1709158438 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImLayout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e54ef13efa2b4641bdfa3070acba78e2 3 | timeCreated: 1708003793 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImRect.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d90eea47c0104db4a0f9699bcc709cac 3 | timeCreated: 1707430583 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImShapes.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3064f7be4d6846288255e11cb2ed00d8 3 | timeCreated: 1718231761 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/IImuiInput.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f0874937a13045fe8b43c73e5560731d 3 | timeCreated: 1716072087 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Rendering.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0ab137b4ea5a4560b5e9e5741c5171b8 3 | timeCreated: 1756323808 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImTheme.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bdd4ff6231b848929e587fd6c8c9c1f3 3 | timeCreated: 1728258109 -------------------------------------------------------------------------------- /Samples~/Scripts/DemoRoot.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c2ba8e6528c5e4e66938af054c416091 3 | timeCreated: 1717794339 -------------------------------------------------------------------------------- /Editor/Scripts/Imui.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7caa0ec8504b418eade9aae0ed61736e 3 | timeCreated: 1739225898 -------------------------------------------------------------------------------- /Editor/Scripts/ImuiUnityGUIBackend.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ceca4d04bf55415d95468b2f59f28b34 3 | timeCreated: 1739225824 -------------------------------------------------------------------------------- /Runtime/Resources/Imui/FiraMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vape/Imui/HEAD/Runtime/Resources/Imui/FiraMono-Regular.ttf -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImButton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54bf63fc2ea747e3bc9e4011ce4fc29a 3 | timeCreated: 1707684480 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImFoldout.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 03e59b20832746399a3e018d98293924 3 | timeCreated: 1717336887 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImGrid.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a3291a95e2124a209ef3d62ed8a4101a 3 | timeCreated: 1717363328 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1710a4c5db224224a200c046b5a4bc22 3 | timeCreated: 1762279114 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImImage.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe628b2a072e46d091f001397608327b 3 | timeCreated: 1717448595 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImList.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1fae70667f774676b2ed524da1258140 3 | timeCreated: 1723380920 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImMenu.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 59e037c302c7487bb86e5566af2c44b6 3 | timeCreated: 1729206358 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImMenuBar.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d6bf06c22691470297f21e7b515fafae 3 | timeCreated: 1729354715 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImPopup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 92259004ae9b4b2aa8c2e80334bd5f73 3 | timeCreated: 1710027042 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImScroll.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 990e08a7fa644b2bb782d824a7ae34af 3 | timeCreated: 1708378177 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImSlider.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ec32ad90355f452c8f279b3d13b82a3a 3 | timeCreated: 1710627794 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 825e5d2d1d6c49a9af6863cc73d0dbc9 3 | timeCreated: 1738499401 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImText.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4f68712e410f4e0ebd71b60c9a0f22d8 3 | timeCreated: 1708003184 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTooltip.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e514deedad8246e6b2ac6a8044fa887f 3 | timeCreated: 1728764416 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTree.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0f361abde8dd47188769f88dc3a948f2 3 | timeCreated: 1724958661 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImVector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6648dfdfca0a47e381f5d48f792404da 3 | timeCreated: 1750110521 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 178ba68d330b48c9a902f79cf144fd54 3 | timeCreated: 1707771381 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImFormatter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b88d4ab6ab37418694413f55237e0f71 3 | timeCreated: 1722993169 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImStorage.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af97e6388989408f80ec5f781b6a2a54 3 | timeCreated: 1731253417 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/IImuiRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ceb74bde88aa46cca204d616902e614c 3 | timeCreated: 1716072093 -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImVertex.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8fa343f511a04a1f9f1f5befc7f272b6 3 | timeCreated: 1707425894 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImAlignment.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d692f314669f46b0bbef7d15fb09936f 3 | timeCreated: 1728580602 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImPadding.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d399ff2cb4f145888703ee409ea7f174 3 | timeCreated: 1709419033 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImStyleSheet.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9add386b093945968790751f77479677 3 | timeCreated: 1720733664 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImAssert.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e986e7eafdd4413898490a1aa110b1bb 3 | timeCreated: 1707427848 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImProfiler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e573d47bd31b44df8dadf6a6f9196b94 3 | timeCreated: 1730573917 -------------------------------------------------------------------------------- /Samples~/Scripts/Imui.Demo.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 72ce1f1d8607f4fec8731163d2b1b46d 3 | timeCreated: 1717794364 -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_ugui.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 15e500d5d2b349b7b59c427e3a1066b7 3 | timeCreated: 1756329598 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImCheckbox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c2741e1b9ab2495680fcee48f7bc4fb5 3 | timeCreated: 1710625650 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImColorButton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9a4bd54a41174bbe805867a200e5eed4 3 | timeCreated: 1730319713 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImColorEdit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 17e2e1060bf74485ae6621d59fa4160d 3 | timeCreated: 1729878074 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImColorPicker.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 54f43b58c1c74db6a401f16976da1342 3 | timeCreated: 1730576976 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImContextMenu.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d11dd875a1174f5d800b4db044b91443 3 | timeCreated: 1731092908 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImDropdown.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f8e798d84abd42f5b66b9fa9845601ef 3 | timeCreated: 1716594315 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImNumericEdit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: decbcabafe104904bb6e914042843a99 3 | timeCreated: 1723063528 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImRadiobox.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3338d21f38274fcd8ce2aaeaeeb58e32 3 | timeCreated: 1723483436 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImSeparator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05551260ca194c32929e756ca10af07b 3 | timeCreated: 1723497149 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTabsPane.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 826b620df2dc48819293427dfaa7a4b5 3 | timeCreated: 1732572362 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTextEdit.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c15910df298b414cb515218d202148cc 3 | timeCreated: 1713989369 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImSize.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7820cefded654c2f90c350068d947350 3 | timeCreated: 1718236755 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImCanvas.Utility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe354e314eab4e6cb0487f07a24c2a93 3 | timeCreated: 1707680604 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImTextSettings.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b2b446ea1ab44044abcbd1dac92e01bc 3 | timeCreated: 1708003532 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImWindowManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6e0bc76f70a0463ab0a13522b1fcda9c 3 | timeCreated: 1709074059 -------------------------------------------------------------------------------- /Runtime/Scripts/Examples/ImDebugWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d1368edc5f83443a835a6cdec5a0e372 3 | timeCreated: 1709407746 -------------------------------------------------------------------------------- /Runtime/Scripts/Examples/ImDemoWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd69492548a54fe291f8106935d44ae2 3 | timeCreated: 1718321917 -------------------------------------------------------------------------------- /Runtime/Scripts/Examples/ImThemeEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eacc3dec74054274b85f85c5805c8070 3 | timeCreated: 1732828356 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImMouseEvent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 152b87449a714f9db8bb9992883db0e0 3 | timeCreated: 1716076731 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImTextEvent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b9cc1e0ff0bc4ec199a531e237aacec6 3 | timeCreated: 1716076756 -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshBuffer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9728f0a390434f9ba72a3524ad2a4460 3 | timeCreated: 1707426452 -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImTextDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb834f2e4efa4ba693e1f85b451dcfdd 3 | timeCreated: 1707591275 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImColorUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cfd61f12e1544b2bb35e59c80aea8292 3 | timeCreated: 1709063288 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImStyleControls.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 129373e4061641ac8414b73e90b5ca1e 3 | timeCreated: 1728578842 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImDynamicArray.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1314832125bf4a8bb9a9c64ab588728e 3 | timeCreated: 1707426618 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImEnumUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed24209e48b241a3acee51d16187e451 3 | timeCreated: 1723483586 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImUnityUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7be1e467d4174c889a960f040494795c 3 | timeCreated: 1725041549 -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_wireframe.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 60fa94c123884577b6990c5fe1336e33 3 | timeCreated: 1751061306 -------------------------------------------------------------------------------- /Runtime/Scripts/Examples/ImConsoleWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7c2a027f19b4050841b5e5745349010 3 | timeCreated: 1723495321 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImKeyboardEvent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8954d0962c4468989a352071269aeef 3 | timeCreated: 1716076741 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Touch/ImTouchKeyboard.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 77feaede17eb4634aa9fbcc0c4ce535e 3 | timeCreated: 1716077547 -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImStyleSheetBuilder.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a0e93ee169542c2a627556d7244ec9f 3 | timeCreated: 1762019374 -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImCircularBuffer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73190c27629a4a54ada92b3f2d07370a 3 | timeCreated: 1715289980 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImDrawingUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b367aa6841204c2ca27dc1fe0aa75292 3 | timeCreated: 1730934467 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImLayoutUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 79ed4f1a646e47bd903dbdaba97f15c3 3 | timeCreated: 1717538010 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImRectUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 18caa0067a894790be58024c3f46b98c 3 | timeCreated: 1707519396 -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImStyleScope.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: add57c70c8304bb2883e4fc3ce284dc4 3 | timeCreated: 1709061930 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImDynamicRenderTexture.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d89da69058f347f0be8f6b313b8407b0 3 | timeCreated: 1716077154 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImUnityInputWrapper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6961151fa6cc447aa8c93f24cd2713c9 3 | timeCreated: 1761692764 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImUnityScrollUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36533918f712417ca1a5992e67be1f15 3 | timeCreated: 1762692342 -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImAxis.cs: -------------------------------------------------------------------------------- 1 | namespace Imui.Core 2 | { 3 | public enum ImAxis 4 | { 5 | Horizontal, 6 | Vertical 7 | } 8 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImKeyboardCommandsHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d167fca784a4dd99308086c629aad21 3 | timeCreated: 1716119417 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Rendering/ImuiBuiltinRenderingScheduler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0be179e4c5ae4d7ebeb8f009f61a1ba4 3 | timeCreated: 1756326446 -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Rendering/ImuiScriptableRenderingScheduler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 07302c31eddf4ec49db4ee7a149c86d2 3 | timeCreated: 1756326571 -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5d92bba4b18054348b90297b1ae7d4c0 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 34d8f9d4e92294079930d8e67f46014f 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 08ab45903fa2c4ad5967bf7ff04321e0 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 512de0efc3a3c415291e3d347203e06a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b3098c2af1bd04561a5e01f72bf0a59d 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Icons.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 70625c9ba11674e2db8f09e12db214f1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97d720bf1ca4146248dccc06b9f8967f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Scripts/Imui.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7cb6614c359f14459a58a452946721b8 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Samples~/Scenes/Imui Demo Scene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a4774bf0d0a142e8b2d91205b4cf834 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d47eb01158cd454e943254daa63b2cf 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_default.shader.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 52e46b7d756bb4c7992012199f744141 3 | ShaderImporter: 4 | externalObjects: {} 5 | defaultTextures: [] 6 | nonModifiableTextures: [] 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImArena.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1e0e5fa063220436c9eece5daba01399 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2adc22bc966a84b1b9724fa063b0aed0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImColorHcl.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f45e9d959285c44ed8ea73f046031039 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89b515a40b9a8465a9cfdd814941da99 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshRenderer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 42f3f8d0056cc469e986c872cf6cacc2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImAlignment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imui.Style 4 | { 5 | [Serializable] 6 | public struct ImAlignment 7 | { 8 | public float X; 9 | public float Y; 10 | 11 | public ImAlignment(float x, float y) 12 | { 13 | X = x; 14 | Y = y; 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/UGUI/ImuiUnityGUIBackend.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c8c999a55a104fa889596b91c6d402cf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: 2800000, guid: 7a2323d217d4244ee836766d2172a8ab, type: 3} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Scripts/Imui.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Imui", 3 | "rootNamespace": "Imui", 4 | "references": [ 5 | "GUID:75469ad4d38634e559750d17036d5f7c" 6 | ], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": true, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Samples~/Scripts/Imui.Demo.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Imui.Demo", 3 | "rootNamespace": "Imui.Demo", 4 | "references": [ 5 | "GUID:7cb6614c359f14459a58a452946721b8" 6 | ], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Editor/Scripts/Imui.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Imui.Editor", 3 | "rootNamespace": "Imui.Editor", 4 | "references": [ 5 | "GUID:7cb6614c359f14459a58a452946721b8" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": true, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": false, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deszz.imui", 3 | "displayName": "Imui", 4 | "description": "IMGUI framework for unity", 5 | "version": "0.8.0", 6 | "unity": "2021.3", 7 | "author": "Artem Sokolov ", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/vape/imui.git" 11 | }, 12 | "samples": [ 13 | { 14 | "displayName": "Sample Scene", 15 | "description": "Demo scene with simple window made with Imui", 16 | "path": "Samples~" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImUnityUtility.cs: -------------------------------------------------------------------------------- 1 | namespace Imui.Utility 2 | { 3 | public static class ImUnityUtility 4 | { 5 | public static void Destroy(UnityEngine.Object obj) 6 | { 7 | #if UNITY_EDITOR 8 | if (UnityEngine.Application.isPlaying) 9 | { 10 | UnityEngine.Object.Destroy(obj); 11 | } 12 | else 13 | { 14 | UnityEngine.Object.DestroyImmediate(obj); 15 | } 16 | #else 17 | UnityEngine.Object.Destroy(obj); 18 | #endif 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Runtime/Resources/Imui/FiraMono-Regular.ttf.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2e9b490edf22d46f080283215ca4034e 3 | TrueTypeFontImporter: 4 | externalObjects: {} 5 | serializedVersion: 4 6 | fontSize: 32 7 | forceTextureCase: -2 8 | characterSpacing: 0 9 | characterPadding: 1 10 | includeFontData: 1 11 | fontNames: 12 | - Fira Mono 13 | fallbackFontReferences: [] 14 | customCharacters: 15 | fontRenderingMode: 0 16 | ascentCalculationMode: 1 17 | useLegacyBoundsCalculation: 0 18 | shouldRoundAdvanceValue: 1 19 | userData: 20 | assetBundleName: 21 | assetBundleVariant: 22 | -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImProfiler.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | using System.Runtime.CompilerServices; 3 | using UnityEngine.Profiling; 4 | 5 | namespace Imui.Utility 6 | { 7 | public static class ImProfiler 8 | { 9 | [Conditional("IMUI_PROFILE")] 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public static void BeginSample(string name) 12 | { 13 | Profiler.BeginSample(name); 14 | } 15 | 16 | [Conditional("IMUI_PROFILE")] 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | public static void EndSample() 19 | { 20 | Profiler.EndSample(); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImDrawingUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace Imui.Controls 8 | { 9 | public static class ImDrawingUtility 10 | { 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public static void Box(this ImGui gui, ImRect rect, in ImStyleBox style) 13 | { 14 | gui.Canvas.RectWithOutline(rect, style.BackColor, style.BorderColor, style.BorderThickness, style.BorderRadius); 15 | } 16 | 17 | public static Vector2Int AsInt(this Vector2 vec2) 18 | { 19 | return new Vector2Int((int)vec2.x, (int)vec2.y); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImColorUtility.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Imui.Style 4 | { 5 | public static class ImColorUtility 6 | { 7 | public static Color WithAlpha(this Color color, float alpha) 8 | { 9 | color.a = Mathf.Clamp01(alpha); 10 | return color; 11 | } 12 | 13 | public static Color32 WithAlpha(this Color32 color, float alpha) 14 | { 15 | color.a = (byte)(255 * Mathf.Clamp01(alpha)); 16 | return color; 17 | } 18 | 19 | public static void SetAlpha(this ref Color32 color, float alpha) 20 | { 21 | color.a = (byte)(255 * Mathf.Clamp01(alpha)); 22 | } 23 | 24 | public static float GetAlpha(this Color32 color) 25 | { 26 | return color.a / 255.0f; 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImKeyboardEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Imui.IO.Events 5 | { 6 | public enum ImKeyboardEventType 7 | { 8 | None, 9 | Down, 10 | Up 11 | } 12 | 13 | public readonly struct ImKeyboardEvent 14 | { 15 | public readonly ImKeyboardEventType Type; 16 | public readonly KeyCode Key; 17 | public readonly EventModifiers Modifiers; 18 | public readonly char Char; 19 | 20 | public ImKeyboardEvent(ImKeyboardEventType type, KeyCode key, EventModifiers modifiers, char c) 21 | { 22 | Type = type; 23 | Key = key; 24 | Modifiers = modifiers; 25 | Char = c; 26 | } 27 | 28 | public override string ToString() 29 | { 30 | return $"type:{Type} key:{Key} mod:{Modifiers} char:{Char}"; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/IImuiRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.Rendering; 4 | 5 | namespace Imui.IO 6 | { 7 | public interface IImuiRenderer 8 | { 9 | Vector2 GetScreenSize(); 10 | float GetScale(); 11 | Vector2Int SetupRenderTarget(CommandBuffer cmd); 12 | void Schedule(IImuiRenderDelegate renderDelegate); 13 | } 14 | 15 | public interface IImuiRenderDelegate 16 | { 17 | void Render(IImuiRenderingContext context); 18 | } 19 | 20 | public interface IImuiRenderingScheduler: IDisposable 21 | { 22 | void Schedule(IImuiRenderDelegate renderDelegate); 23 | } 24 | 25 | public interface IImuiRenderingContext : IDisposable 26 | { 27 | CommandBuffer CreateCommandBuffer(); 28 | void ReleaseCommandBuffer(CommandBuffer cmd); 29 | void ExecuteCommandBuffer(CommandBuffer cmd); 30 | } 31 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImAssert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using UnityEngine; 4 | 5 | // ReSharper disable CheckNamespace 6 | 7 | internal class ImuiAssertException: Exception 8 | { 9 | public ImuiAssertException(string message): base(message) { } 10 | } 11 | 12 | internal static class ImAssert 13 | { 14 | #if UNITY_2022_2_OR_NEWER 15 | [HideInCallstack] 16 | #endif 17 | [Conditional("IMUI_DEBUG")] 18 | public static void IsTrue(bool value, string message) 19 | { 20 | if (!value) 21 | { 22 | throw new ImuiAssertException(message); 23 | } 24 | } 25 | 26 | #if UNITY_2022_2_OR_NEWER 27 | [HideInCallstack] 28 | #endif 29 | [Conditional("IMUI_DEBUG")] 30 | public static void IsFalse(bool value, string message) 31 | { 32 | if (value) 33 | { 34 | throw new ImuiAssertException(message); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImUnityScrollUtility.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_WEBGL && !UNITY_EDITOR 2 | #define WEBGL_BUILD 3 | #endif 4 | 5 | using UnityEngine; 6 | 7 | #if ENABLE_INPUT_SYSTEM 8 | using UnityEngine.EventSystems; 9 | using UnityEngine.InputSystem.UI; 10 | #endif 11 | 12 | namespace Imui.IO.Utility 13 | { 14 | public static class ImUnityScrollUtility 15 | { 16 | public static Vector2 ProcessScrollDelta(float dx, float dy) 17 | { 18 | #if ENABLE_INPUT_SYSTEM || WEBGL_BUILD 19 | dx = -dx; 20 | #endif 21 | 22 | #if ENABLE_INPUT_SYSTEM 23 | var eventSystem = EventSystem.current?.currentInputModule as InputSystemUIInputModule; 24 | if (eventSystem) 25 | { 26 | dx /= eventSystem.scrollDeltaPerTick; 27 | dy /= eventSystem.scrollDeltaPerTick; 28 | } 29 | #endif 30 | 31 | return new Vector2(dx, dy); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Editor/Scripts/ImuiUnityGUIBackend.cs: -------------------------------------------------------------------------------- 1 | using Imui.IO.UGUI; 2 | using UnityEditor; 3 | 4 | namespace Imui.Editor.Scripts 5 | { 6 | [CustomEditor(typeof(IO.UGUI.ImuiUnityGUIBackend))] 7 | public class ImuiUnityGUIBackend : UnityEditor.Editor 8 | { 9 | public override void OnInspectorGUI() 10 | { 11 | var raycastTarget = serializedObject.FindProperty("m_RaycastTarget"); 12 | var scalingMode = serializedObject.FindProperty("scalingMode"); 13 | var customScale = serializedObject.FindProperty("customScale"); 14 | 15 | EditorGUILayout.PropertyField(raycastTarget); 16 | EditorGUILayout.PropertyField(scalingMode); 17 | 18 | if (scalingMode.intValue == (int)IO.UGUI.ImuiUnityGUIBackend.ScalingMode.Custom) 19 | { 20 | EditorGUILayout.PropertyField(customScale); 21 | } 22 | 23 | serializedObject.ApplyModifiedProperties(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImTextSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Rendering; 3 | using Imui.Style; 4 | 5 | namespace Imui.Core 6 | { 7 | [Serializable] 8 | public struct ImTextSettings 9 | { 10 | public float Size; 11 | public ImAlignment Align; 12 | public bool Wrap; 13 | public ImTextOverflow Overflow; 14 | 15 | public ImTextSettings(float size, float alignX = 0.0f, float alignY = 0.0f, bool wrap = false, ImTextOverflow overflow = ImTextOverflow.Overflow) 16 | { 17 | Size = size; 18 | Align.X = alignX; 19 | Align.Y = alignY; 20 | Wrap = wrap; 21 | Overflow = overflow; 22 | } 23 | 24 | public ImTextSettings(float size, ImAlignment alignment, bool wrap = false, ImTextOverflow overflow = ImTextOverflow.Overflow) 25 | { 26 | Size = size; 27 | Align = alignment; 28 | Wrap = wrap; 29 | Overflow = overflow; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImTextEvent.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Imui.IO.Events 4 | { 5 | public enum ImTextEventType 6 | { 7 | None, 8 | Cancel, 9 | Submit, 10 | Set 11 | } 12 | 13 | public readonly struct ImTextEvent 14 | { 15 | public readonly ImTextEventType Type; 16 | public readonly string Text; 17 | public readonly RangeInt? Selection; 18 | 19 | public ImTextEvent(ImTextEventType type, RangeInt? selection = null) 20 | { 21 | Type = type; 22 | Text = null; 23 | Selection = selection; 24 | } 25 | 26 | public ImTextEvent(ImTextEventType type, string text, RangeInt? selection = null) 27 | { 28 | Type = type; 29 | Text = text; 30 | Selection = selection; 31 | } 32 | 33 | public override string ToString() 34 | { 35 | return $"type:{Type} text:{Text}"; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Artem Sokolov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Runtime/Scripts/IO/IImuiInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.IO.Events; 3 | using Imui.IO.Touch; 4 | using UnityEngine; 5 | 6 | namespace Imui.IO 7 | { 8 | public interface IImuiInput 9 | { 10 | public delegate bool RaycasterDelegate(float x, float y); 11 | 12 | string Clipboard 13 | { 14 | get { return GUIUtility.systemCopyBuffer ?? string.Empty; } 15 | set { GUIUtility.systemCopyBuffer = value; } 16 | } 17 | 18 | Vector2 MousePosition { get; } 19 | double Time { get; } 20 | 21 | bool WasMouseDownThisFrame { get; } 22 | 23 | ref readonly ImMouseEvent MouseEvent { get; } 24 | void UseMouseEvent(); 25 | 26 | ref readonly ImTextEvent TextEvent { get; } 27 | void UseTextEvent(); 28 | 29 | int KeyboardEventsCount { get; } 30 | ref readonly ImKeyboardEvent GetKeyboardEvent(int index); 31 | void UseKeyboardEvent(int index); 32 | void RequestTouchKeyboard(uint owner, ReadOnlySpan text, ImTouchKeyboardSettings settings); 33 | 34 | void UseRaycaster(RaycasterDelegate raycaster); 35 | void Pull(); 36 | } 37 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImStyleSheet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imui.Style 4 | { 5 | public struct ImStyleGlobal 6 | { 7 | public float ReadOnlyModifier; 8 | public float EmbeddedButtonPadding; 9 | } 10 | 11 | [Serializable] 12 | public struct ImStyleSheet 13 | { 14 | public ImStyleGlobal Global; 15 | public ImStyleLayout Layout; 16 | public ImStyleWindow Window; 17 | public ImStyleText Text; 18 | public ImStyleButton Button; 19 | public ImStyleButton AccentButton; 20 | public ImStyleCheckbox Checkbox; 21 | public ImStyleFoldout Foldout; 22 | public ImStyleScrollbar Scroll; 23 | public ImStyleTextEdit TextEdit; 24 | public ImStyleDropdown Dropdown; 25 | public ImStyleSlider Slider; 26 | public ImStyleList List; 27 | public ImStyleRadiobox Radiobox; 28 | public ImStyleSeparator Separator; 29 | public ImStyleTree Tree; 30 | public ImStyleTooltip Tooltip; 31 | public ImStyleMenu Menu; 32 | public ImStyleMenuBar MenuBar; 33 | public ImStyleColorPicker ColorPicker; 34 | public ImStyleTab Tabs; 35 | public ImStyleTable Table; 36 | } 37 | } -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_wireframe.shader: -------------------------------------------------------------------------------- 1 | Shader "Hidden/Imui/Wireframe" 2 | { 3 | Properties 4 | { } 5 | 6 | SubShader 7 | { 8 | Tags { "RenderType" = "Transparent" } 9 | Blend SrcAlpha OneMinusSrcAlpha, SrcAlpha One 10 | ZTest LEqual 11 | ZWrite On 12 | Cull Back 13 | 14 | Pass 15 | { 16 | CGPROGRAM 17 | 18 | #pragma vertex vert 19 | #pragma fragment frag 20 | 21 | struct appdata 22 | { 23 | float3 vertex : POSITION; 24 | float4 color : COLOR; 25 | float2 uv : TEXCOORD0; 26 | float atlas : TEXCOORD1; 27 | }; 28 | 29 | struct v2f 30 | { 31 | float4 vertex : SV_POSITION; 32 | }; 33 | 34 | float4x4 _VP; 35 | 36 | v2f vert(appdata data) 37 | { 38 | v2f o; 39 | o.vertex = mul(_VP, float4(data.vertex, 1.0)); 40 | return o; 41 | } 42 | 43 | fixed4 frag(const v2f i) : SV_Target 44 | { 45 | return float4(0.0, 0.0, 0.0, 1.0); 46 | } 47 | 48 | ENDCG 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Events/ImMouseEvent.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Imui.IO.Events 4 | { 5 | public enum ImMouseEventType 6 | { 7 | None, 8 | Down, 9 | Up, 10 | Move, 11 | Scroll, 12 | BeginDrag, 13 | Drag, 14 | Hold, 15 | Click 16 | } 17 | 18 | public enum ImMouseDevice 19 | { 20 | Unknown, 21 | Mouse, 22 | Touch 23 | } 24 | 25 | public readonly struct ImMouseEvent 26 | { 27 | public readonly ImMouseEventType Type; 28 | public readonly int Button; 29 | public readonly EventModifiers Modifiers; 30 | public readonly Vector2 Delta; 31 | public readonly int Count; 32 | public readonly bool LeftButton; 33 | public readonly ImMouseDevice Device; 34 | 35 | public ImMouseEvent(ImMouseEventType type, int button, EventModifiers modifiers, Vector2 delta, ImMouseDevice device, int count = 1) 36 | { 37 | Type = type; 38 | Button = button; 39 | Modifiers = modifiers; 40 | Delta = delta; 41 | Count = count; 42 | LeftButton = button == 0; 43 | Device = device; 44 | } 45 | 46 | public override string ToString() 47 | { 48 | return $"type:{Type} btn:{Button} mod:{Modifiers} dt:{Delta} count:{Count} device:{Device}"; 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImSize.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace Imui.Controls 5 | { 6 | public enum ImSizeMode 7 | { 8 | Auto = 0, 9 | Fixed = 1, 10 | Fit = 2, 11 | Fill = 3 12 | } 13 | 14 | public struct ImSize 15 | { 16 | public float Width; 17 | public float Height; 18 | public ImSizeMode Mode; 19 | 20 | public ImSize(float width, float height, ImSizeMode mode) 21 | { 22 | Width = width; 23 | Height = height; 24 | Mode = mode; 25 | } 26 | 27 | public ImSize(float width, float height) 28 | { 29 | Width = width; 30 | Height = height; 31 | Mode = ImSizeMode.Fixed; 32 | } 33 | 34 | public ImSize(ImSizeMode mode) 35 | { 36 | Width = 0; 37 | Height = 0; 38 | Mode = mode; 39 | } 40 | 41 | public static implicit operator ImSize(Vector2 size) 42 | { 43 | return new ImSize(size.x, size.y); 44 | } 45 | 46 | public static implicit operator ImSize((float width, float height) size) 47 | { 48 | return new ImSize(size.width, size.height); 49 | } 50 | 51 | public static implicit operator ImSize(ImSizeMode mode) 52 | { 53 | return new ImSize(mode); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshData.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Imui.Rendering 4 | { 5 | public struct ImMeshClipRect 6 | { 7 | public bool Enabled; 8 | public Rect Rect; 9 | } 10 | 11 | public struct ImMeshMaskRect 12 | { 13 | public bool Enabled; 14 | public Rect Rect; 15 | public float Radius; 16 | } 17 | 18 | public struct ImMeshData 19 | { 20 | public Texture MainTex; 21 | public Texture FontTex; 22 | public Material Material; 23 | public int IndicesOffset; 24 | public int VerticesOffset; 25 | public int VerticesCount; 26 | public int IndicesCount; 27 | public MeshTopology Topology; 28 | public int Order; 29 | public ImMeshClipRect ClipRect; 30 | public ImMeshMaskRect MaskRect; 31 | public float InvColorMul; 32 | 33 | public void ClearOptions() 34 | { 35 | MainTex = null; 36 | FontTex = null; 37 | Material = null; 38 | Topology = default; 39 | Order = 0; 40 | ClipRect = default; 41 | MaskRect = default; 42 | InvColorMul = default; 43 | } 44 | 45 | public void Clear() 46 | { 47 | IndicesOffset = 0; 48 | VerticesOffset = 0; 49 | VerticesCount = 0; 50 | IndicesCount = 0; 51 | 52 | ClearOptions(); 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImVertex.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using UnityEngine; 3 | using UnityEngine.Rendering; 4 | 5 | // ReSharper disable RedundantArgumentDefaultValue 6 | 7 | namespace Imui.Rendering 8 | { 9 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 10 | public struct ImVertex 11 | { 12 | public static readonly VertexAttributeDescriptor[] VertexAttributes = new VertexAttributeDescriptor[] 13 | { 14 | new VertexAttributeDescriptor(VertexAttribute.Position, VertexAttributeFormat.Float32, 2), 15 | new VertexAttributeDescriptor(VertexAttribute.Color, VertexAttributeFormat.UNorm8, 4), 16 | new VertexAttributeDescriptor(VertexAttribute.TexCoord0, VertexAttributeFormat.Float32, 2), 17 | new VertexAttributeDescriptor(VertexAttribute.TexCoord1, VertexAttributeFormat.Float32, 1) 18 | }; 19 | 20 | public Vector2 Position; 21 | public Color32 Color; 22 | public Vector2 UV; 23 | public float Atlas; 24 | 25 | public ImVertex(Vector2 position, Color32 color, Vector2 uv, float atlas) 26 | { 27 | Position = position; 28 | Color = color; 29 | UV = uv; 30 | Atlas = atlas; 31 | } 32 | 33 | public ImVertex(ImVertex vertex) 34 | { 35 | Position = vertex.Position; 36 | Color = vertex.Color; 37 | UV = vertex.UV; 38 | Atlas = vertex.Atlas; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Rendering/ImuiBuiltinRenderingScheduler.cs: -------------------------------------------------------------------------------- 1 | using Imui.Utility; 2 | using UnityEngine; 3 | using UnityEngine.Rendering; 4 | 5 | namespace Imui.IO.Rendering 6 | { 7 | public class ImuiBuiltinRenderingScheduler : IImuiRenderingScheduler, IImuiRenderingContext 8 | { 9 | private ImDynamicArray commandBufferPool = new(2); 10 | 11 | public void Schedule(IImuiRenderDelegate renderDelegate) 12 | { 13 | renderDelegate.Render(this); 14 | } 15 | 16 | public CommandBuffer CreateCommandBuffer() 17 | { 18 | if (commandBufferPool.Count == 0) 19 | { 20 | var cmd = new CommandBuffer() { name = "Imui (Builtin)" }; 21 | commandBufferPool.Add(cmd); 22 | } 23 | 24 | return commandBufferPool.Pop(); 25 | } 26 | 27 | public void ReleaseCommandBuffer(CommandBuffer cmd) 28 | { 29 | cmd.Clear(); 30 | commandBufferPool.Add(cmd); 31 | } 32 | 33 | public void ExecuteCommandBuffer(CommandBuffer cmd) 34 | { 35 | Graphics.ExecuteCommandBuffer(cmd); 36 | } 37 | 38 | public void Dispose() 39 | { 40 | for (int i = 0; i < commandBufferPool.Count; ++i) 41 | { 42 | commandBufferPool.Array[i].Release(); 43 | } 44 | 45 | commandBufferPool.Clear(false); 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImStyleScope.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using Imui.Core; 3 | 4 | namespace Imui.Style 5 | { 6 | public ref struct ImStyleScope where T: unmanaged 7 | { 8 | private ImGui gui; 9 | private bool disposed; 10 | 11 | public ImStyleScope(ImGui gui, ref T property, in T style) 12 | { 13 | this.gui = gui; 14 | this.gui.PushStyle(ref property, in style); 15 | 16 | disposed = false; 17 | } 18 | 19 | public ImStyleScope(ImGui gui, ref T property) 20 | { 21 | this.gui = gui; 22 | this.gui.PushStyle(ref property); 23 | 24 | disposed = false; 25 | } 26 | 27 | public void Dispose() 28 | { 29 | if (disposed) 30 | { 31 | return; 32 | } 33 | 34 | gui.PopStyle(); 35 | } 36 | } 37 | 38 | public static class ImControlStyleExtensions 39 | { 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | public static ImStyleScope StyleScope(this ImGui gui, ref T prop, in T style) where T: unmanaged 42 | { 43 | return new ImStyleScope(gui, ref prop, in style); 44 | } 45 | 46 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 47 | public static ImStyleScope StyleScope(this ImGui gui, ref T prop) where T: unmanaged 48 | { 49 | return new ImStyleScope(gui, ref prop); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Imui 2 | 3 | Immediate mode GUI framework made specifically for Unity. Written in pure C#, has zero per-frame allocations, is somewhat performant, has no external dependencies, and works on basically any platform that Unity supports and that has either a touchscreen or mouse and keyboard. A WebGL demo can be seen [here](https://vape.github.io/imui_demo_080/). 4 | 5 | ## Screenshot 6 | 7 | ![Screenshot](https://raw.githubusercontent.com/vape/Imui/screenshots/Screenshots/screenshot_4.png) 8 | 9 | ## How it works 10 | 11 | The basic principle is the same as in Dear ImGui: every frame, we generate a mesh with all the controls in it, split into different draw calls when needed, and render it to the render texture. For simple cases, the UI can be drawn with a single draw call (when no masks or different materials are involved). Using the `ImuiUnityGUIBackend` component, the whole UI can be integrated into the `Canvas` hierarchy and used like any other UGUI component. 12 | 13 | ## Installation 14 | 15 | You can install Imui as a git package in Unity Package Manager 16 | 17 | ## Supported Controls 18 | 19 | * Window 20 | * Button 21 | * Checkbox 22 | * Slider 23 | * Label 24 | * Image 25 | * Text/Number Editor 26 | * Dropdown 27 | * Scroll Bar 28 | * Foldout 29 | * Separator 30 | * Tree 31 | * Radio Group 32 | * Listbox 33 | * Menu 34 | * Tooltip 35 | * Color Picker 36 | * Tabs Pane 37 | * Table 38 | 39 | ## Notes 40 | 41 | At this stage, it's not ready for, well, anything except poking and tweaking around. Any existing API could be changed anytime if I have the desire or time to continue developing it. 42 | -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImAABB.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Imui.Core 4 | { 5 | public struct ImAABB 6 | { 7 | public float Left; 8 | public float Top; 9 | public float Right; 10 | public float Bottom; 11 | 12 | public ImAABB(float left, float top, float right, float bottom) 13 | { 14 | Left = left; 15 | Top = top; 16 | Right = right; 17 | Bottom = bottom; 18 | } 19 | 20 | public ImAABB(ImRect rect) 21 | { 22 | Left = rect.X; 23 | Top = rect.Top; 24 | Right = rect.Right; 25 | Bottom = rect.Y; 26 | } 27 | } 28 | 29 | public static class ImAABBExtensions 30 | { 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static bool Overlaps(this ref ImAABB self, in ImAABB other) 33 | { 34 | return 35 | other.Right > self.Left & 36 | other.Left < self.Right & 37 | other.Top > self.Bottom & 38 | other.Bottom < self.Top; 39 | } 40 | 41 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 42 | public static bool Overlaps(this ref ImAABB self, in ImRect other) 43 | { 44 | var right = other.X + other.W; 45 | var top = other.Y + other.H; 46 | 47 | return 48 | right > self.Left & 49 | other.X < self.Right & 50 | top > self.Bottom & 51 | other.Y < self.Top; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImContextMenu.cs: -------------------------------------------------------------------------------- 1 | using Imui.Core; 2 | using Imui.IO.Events; 3 | using UnityEngine; 4 | 5 | namespace Imui.Controls 6 | { 7 | public struct ImContextMenuState 8 | { 9 | public bool Open; 10 | public Vector2 Source; 11 | } 12 | 13 | public static class ImContextMenu 14 | { 15 | public static bool BeginContextMenu(this ImGui gui, ImRect clickableArea) 16 | { 17 | var id = gui.GetNextControlId(); 18 | ref var state = ref gui.Storage.Get(id); 19 | 20 | gui.RegisterGroup(id, clickableArea); 21 | 22 | ref readonly var evt = ref gui.Input.MouseEvent; 23 | if (!state.Open && gui.IsGroupHovered(id) && evt is { Type: ImMouseEventType.Down, Button: 1 }) 24 | { 25 | state.Open = true; 26 | state.Source = gui.Input.MousePosition; 27 | 28 | gui.Input.UseMouseEvent(); 29 | } 30 | 31 | return BeginContextMenu(gui, id, state.Source, ref state.Open); 32 | } 33 | 34 | public static bool BeginContextMenu(this ImGui gui, uint id, Vector2 source, ref bool open) 35 | { 36 | gui.PushId(id); 37 | 38 | if (!gui.BeginMenuPopup("context_menu", ref open, source)) 39 | { 40 | gui.PopId(); 41 | return false; 42 | } 43 | 44 | return true; 45 | } 46 | 47 | public static void EndContextMenu(this ImGui gui) 48 | { 49 | gui.EndMenuPopup(); 50 | 51 | gui.PopId(); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /Samples~/Scripts/DemoRoot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Controls; 3 | using Imui.Core; 4 | using Imui.Examples; 5 | using Imui.IO.UGUI; 6 | using UnityEngine; 7 | 8 | namespace Imui.Demo 9 | { 10 | public class DemoRoot : MonoBehaviour 11 | { 12 | [SerializeField] private Camera cam; 13 | [SerializeField] private Canvas canvas; 14 | [SerializeField] private ImuiUnityGUIBackend backend; 15 | 16 | private ImGui gui; 17 | private bool demoOpen = true; 18 | 19 | private void OnEnable() 20 | { 21 | gui = new ImGui(backend, backend); 22 | } 23 | 24 | private void OnDisable() 25 | { 26 | gui?.Dispose(); 27 | } 28 | 29 | private void Update() 30 | { 31 | gui.BeginFrame(); 32 | 33 | DrawRootMenu(); 34 | ImDemoWindow.Draw(gui, ref demoOpen); 35 | 36 | gui.EndFrame(); 37 | gui.Render(); 38 | } 39 | 40 | private void DrawRootMenu() 41 | { 42 | gui.BeginMenuBar(); 43 | 44 | if (gui.BeginMenu("Demo")) 45 | { 46 | gui.Menu("Show Demo", ref demoOpen); 47 | gui.EndMenu(); 48 | } 49 | 50 | if (gui.BeginMenu("View")) 51 | { 52 | gui.AddSpacingIfLayoutFrameNotEmpty(); 53 | gui.BeginHorizontal(); 54 | gui.Text("Clear Color"); 55 | gui.AddSpacing(20); 56 | cam.backgroundColor = gui.ColorEdit(cam.backgroundColor); 57 | gui.EndHorizontal(); 58 | gui.EndMenu(); 59 | } 60 | 61 | gui.EndMenuBar(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Asset meta data should only be ignored when the corresponding asset is also ignored 18 | !/[Aa]ssets/**/*.meta 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Idea cache directory 30 | .idea/ 31 | 32 | # MacOS files 33 | *.DS_Store 34 | 35 | # Gradle cache directory 36 | .gradle/ 37 | 38 | # Autogenerated VS/MD/Consulo solution and project files 39 | ExportedObj/ 40 | .consulo/ 41 | *.csproj 42 | *.unityproj 43 | *.sln 44 | *.suo 45 | *.tmp 46 | *.user 47 | *.userprefs 48 | *.pidb 49 | *.booproj 50 | *.svd 51 | *.pdb 52 | *.mdb 53 | *.opendb 54 | *.VC.db 55 | 56 | # Unity3D generated meta files 57 | *.pidb.meta 58 | *.pdb.meta 59 | *.mdb.meta 60 | 61 | # Unity3D generated file on crash reports 62 | sysinfo.txt 63 | 64 | # Builds 65 | *.apk 66 | *.aab 67 | *.unitypackage 68 | 69 | # Crashlytics generated file 70 | crashlytics-build.properties 71 | 72 | # Remote Addressables Bundles 73 | /[Ss]erverData/* 74 | 75 | # Temporary auto-generated Android Assets 76 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 77 | /[Aa]ssets/[Ss]treamingAssets/aa/* 78 | 79 | # Addressables auto-generated link.xml 80 | /[Aa]ssets/AddressableAssetsData/link.xml 81 | /[Aa]ssets/AddressableAssetsData/link.xml.meta -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImUnityInputWrapper.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | #if ENABLE_INPUT_SYSTEM 4 | using UnityEngine.InputSystem; 5 | #endif 6 | 7 | namespace Imui.IO.Utility 8 | { 9 | public static class ImUnityInputWrapper 10 | { 11 | #if ENABLE_INPUT_SYSTEM 12 | public static Vector2 MousePosition => Mouse.current?.position?.value ?? Touchscreen.current?.position?.value ?? default; 13 | public static bool TouchScreenSupported => Touchscreen.current?.enabled ?? false; 14 | public static bool IsControlPressed => Keyboard.current?.ctrlKey.isPressed ?? false; 15 | 16 | public static bool IsTouchBeganThisFrame() 17 | { 18 | var touchscreen = Touchscreen.current; 19 | if (touchscreen == null) 20 | { 21 | return false; 22 | } 23 | 24 | var touches = touchscreen.touches; 25 | for (int i = 0; i < touches.Count; ++i) 26 | { 27 | if (touches[i].phase.value == UnityEngine.InputSystem.TouchPhase.Began) 28 | { 29 | return true; 30 | } 31 | } 32 | 33 | return false; 34 | } 35 | #else 36 | public static Vector2 MousePosition => Input.mousePosition; 37 | public static bool TouchScreenSupported => Input.touchSupported; 38 | public static bool IsControlPressed => Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl); 39 | 40 | public static bool IsTouchBeganThisFrame() 41 | { 42 | var count = Input.touchCount; 43 | 44 | for (int i = 0; i < count; ++i) 45 | { 46 | if (Input.GetTouch(i).phase == UnityEngine.TouchPhase.Began) 47 | { 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | #endif 55 | } 56 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Rendering/ImuiScriptableRenderingScheduler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Imui.Utility; 3 | using UnityEngine; 4 | using UnityEngine.Rendering; 5 | 6 | namespace Imui.IO.Rendering 7 | { 8 | public class ImuiScriptableRenderingScheduler : IImuiRenderingScheduler, IImuiRenderingContext 9 | { 10 | private Queue queue = new(1); 11 | private ImDynamicArray commandBufferPool = new(1); 12 | private ScriptableRenderContext activeContext; 13 | 14 | public ImuiScriptableRenderingScheduler() 15 | { 16 | RenderPipelineManager.beginCameraRendering += OnBeginCameraRendering; 17 | } 18 | 19 | public void Schedule(IImuiRenderDelegate renderDelegate) 20 | { 21 | queue.Enqueue(renderDelegate); 22 | } 23 | 24 | public CommandBuffer CreateCommandBuffer() 25 | { 26 | if (commandBufferPool.Count == 0) 27 | { 28 | var cmd = new CommandBuffer() { name = "Imui (SRP)" }; 29 | commandBufferPool.Add(cmd); 30 | } 31 | 32 | return commandBufferPool.Pop(); 33 | } 34 | 35 | public void ReleaseCommandBuffer(CommandBuffer cmd) 36 | { 37 | cmd.Clear(); 38 | commandBufferPool.Push(cmd); 39 | } 40 | 41 | public void ExecuteCommandBuffer(CommandBuffer cmd) 42 | { 43 | activeContext.ExecuteCommandBuffer(cmd); 44 | } 45 | 46 | private void OnBeginCameraRendering(ScriptableRenderContext context, Camera camera) 47 | { 48 | activeContext = context; 49 | 50 | while (queue.TryDequeue(out var renderDelegate)) 51 | { 52 | renderDelegate.Render(this); 53 | } 54 | 55 | activeContext = default; 56 | } 57 | 58 | public void Dispose() 59 | { 60 | RenderPipelineManager.beginCameraRendering -= OnBeginCameraRendering; 61 | queue.Clear(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImPadding.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imui.Style 4 | { 5 | [Serializable] 6 | public struct ImPadding 7 | { 8 | public float Vertical => Top + Bottom; 9 | public float Horizontal => Left + Right; 10 | 11 | public float Left; 12 | public float Right; 13 | public float Top; 14 | public float Bottom; 15 | 16 | public ImPadding(float padding): this(padding, padding, padding, padding) { } 17 | 18 | public ImPadding(float left, float right, float top, float bottom) 19 | { 20 | Left = left; 21 | Right = right; 22 | Top = top; 23 | Bottom = bottom; 24 | } 25 | 26 | public void Add(float value) 27 | { 28 | Left += value; 29 | Right += value; 30 | Top += value; 31 | Bottom += value; 32 | } 33 | 34 | public void Add(in ImPadding padding) 35 | { 36 | Left += padding.Left; 37 | Right += padding.Right; 38 | Top += padding.Top; 39 | Bottom += padding.Bottom; 40 | } 41 | 42 | public static implicit operator ImPadding(float padding) => new(padding); 43 | 44 | public static ImPadding operator +(ImPadding padding, float value) 45 | { 46 | padding.Add(value); 47 | return padding; 48 | } 49 | 50 | public static ImPadding operator +(ImPadding padding, in ImPadding value) 51 | { 52 | padding.Add(in value); 53 | return padding; 54 | } 55 | 56 | public static ImPadding operator -(ImPadding padding, float value) 57 | { 58 | padding.Add(-value); 59 | return padding; 60 | } 61 | 62 | public static ImPadding operator -(ImPadding padding) 63 | { 64 | padding.Left = -padding.Left; 65 | padding.Right = -padding.Right; 66 | padding.Top = -padding.Top; 67 | padding.Bottom = -padding.Bottom; 68 | return padding; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTooltip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using UnityEngine; 4 | 5 | namespace Imui.Controls 6 | { 7 | [Flags] 8 | public enum ImTooltipShow 9 | { 10 | None = 0, 11 | OnHover = 1 << 0, 12 | OnActive = 1 << 1 13 | } 14 | 15 | public static class ImTooltip 16 | { 17 | public static void TooltipAtLastControl(this ImGui gui, ReadOnlySpan text, ImTooltipShow show = ImTooltipShow.OnHover) 18 | { 19 | TooltipAtControl(gui, gui.LastControl, text, show); 20 | } 21 | 22 | public static void TooltipAtControl(this ImGui gui, uint control, ReadOnlySpan text, ImTooltipShow show = ImTooltipShow.OnHover) 23 | { 24 | var shouldShow = false; 25 | 26 | shouldShow |= (show & ImTooltipShow.OnHover) != 0 && gui.IsControlHovered(control); 27 | shouldShow |= (show & ImTooltipShow.OnActive) != 0 && gui.IsControlActive(control); 28 | 29 | if (!shouldShow) 30 | { 31 | return; 32 | } 33 | 34 | Tooltip(gui, text, gui.Input.MousePosition + gui.Style.Tooltip.OffsetPixels / gui.Canvas.ScreenScale); 35 | } 36 | 37 | public static void Tooltip(this ImGui gui, ReadOnlySpan text, Vector2 position) 38 | { 39 | var textSettings = GetTextSettings(gui); 40 | var textSize = gui.MeasureTextSize(text, textSettings); 41 | var width = textSize.x + gui.Style.Tooltip.Padding.Horizontal; 42 | var height = textSize.y + gui.Style.Tooltip.Padding.Vertical; 43 | var rect = new ImRect(position.x, gui.Style.Tooltip.AboveCursor ? position.y : position.y - height, width, height); 44 | 45 | Tooltip(gui, text, rect); 46 | } 47 | 48 | public static void Tooltip(this ImGui gui, ReadOnlySpan text, ImRect rect) 49 | { 50 | gui.BeginPopup(); 51 | gui.Box(rect, gui.Style.Tooltip.Box); 52 | gui.Text(text, GetTextSettings(gui), rect); 53 | gui.EndPopup(); 54 | } 55 | 56 | public static ImTextSettings GetTextSettings(ImGui gui) 57 | { 58 | return new ImTextSettings(gui.Style.Layout.TextSize, 0.5f, 0.5f); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImPopup.cs: -------------------------------------------------------------------------------- 1 | using Imui.Core; 2 | using Imui.IO.Events; 3 | using UnityEngine; 4 | 5 | namespace Imui.Controls 6 | { 7 | public static class ImPopup 8 | { 9 | public const int POPUP_BASE_ORDER = 1024 * 1024; // above all windows, well, if you're not doing like 8191+ of them 10 | public const int POPUP_ORDER_STEP = 1024; 11 | public const int POPUP_CLOSE_BUTTON_ORDER_OFFSET = -16; 12 | 13 | public static void BeginPopup(this ImGui gui) 14 | { 15 | var overBaseOrder = Mathf.Max(0, gui.Canvas.GetOrder() - POPUP_BASE_ORDER); 16 | var order = POPUP_BASE_ORDER + ((overBaseOrder / POPUP_ORDER_STEP) * POPUP_ORDER_STEP + POPUP_ORDER_STEP); 17 | 18 | gui.Canvas.PushNoClipRect(); 19 | gui.Canvas.PushNoRectMask(); 20 | gui.Canvas.PushOrder(order); 21 | } 22 | 23 | public static void EndPopup(this ImGui gui) 24 | { 25 | gui.Canvas.PopOrder(); 26 | gui.Canvas.PopClipRect(); 27 | gui.Canvas.PopRectMask(); 28 | } 29 | 30 | public static void EndPopupWithCloseButton(this ImGui gui, out bool close) 31 | { 32 | var order = gui.Canvas.GetOrder() + POPUP_CLOSE_BUTTON_ORDER_OFFSET; 33 | 34 | gui.Canvas.PopOrder(); 35 | gui.Canvas.PopClipRect(); 36 | gui.Canvas.PopRectMask(); 37 | 38 | close = CloseButton(gui, order); 39 | } 40 | 41 | public static bool CloseButton(ImGui gui, int order) 42 | { 43 | gui.Canvas.PushNoClipRect(); 44 | gui.Canvas.PushOrder(order); 45 | gui.RegisterRaycastTarget(gui.Canvas.ScreenRect); 46 | 47 | var id = gui.GetNextControlId(); 48 | 49 | ref readonly var mouseEvent = ref gui.Input.MouseEvent; 50 | if (mouseEvent.Type == ImMouseEventType.Scroll || mouseEvent.Type == ImMouseEventType.Drag) 51 | { 52 | gui.Input.UseMouseEvent(); 53 | } 54 | 55 | var clicked = gui.InvisibleButton(id, gui.Canvas.ScreenRect, ImButtonFlag.ActOnPress | ImButtonFlag.ReactToAnyButton); 56 | 57 | gui.Canvas.PopOrder(); 58 | gui.Canvas.PopClipRect(); 59 | 60 | return clicked; 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | 5 | namespace Imui.Controls 6 | { 7 | // TODO (artem-s): add optional titlebar 8 | public static class ImList 9 | { 10 | public static void BeginList(this ImGui gui, ImSize size = default) 11 | { 12 | gui.AddSpacingIfLayoutFrameNotEmpty(); 13 | 14 | BeginList(gui, gui.AddSingleRowRect(size)); 15 | } 16 | 17 | public static void BeginList(this ImGui gui, ImRect rect) 18 | { 19 | gui.Box(rect, gui.Style.List.Box); 20 | gui.RegisterRaycastTarget(rect); 21 | 22 | var layoutRect = rect.WithPadding(gui.Style.List.Padding); 23 | var maskRect = rect.WithPadding(gui.Style.List.Box.BorderThickness); 24 | 25 | gui.Layout.Push(ImAxis.Vertical, layoutRect); 26 | gui.Canvas.PushRectMask(maskRect, gui.Style.List.Box.BorderRadius); 27 | gui.Canvas.PushClipRect(maskRect); // need this to properly handle clicking outside drawing area 28 | gui.BeginScrollable(); 29 | } 30 | 31 | public static void EndList(this ImGui gui) 32 | { 33 | gui.EndScrollable(); 34 | gui.Canvas.PopClipRect(); 35 | gui.Canvas.PopRectMask(); 36 | gui.Layout.Pop(); 37 | } 38 | 39 | public static bool ListItem(this ImGui gui, ref int selectedIndex, int index, ReadOnlySpan label) 40 | { 41 | ref readonly var style = ref (index == selectedIndex ? ref gui.Style.List.ItemSelected : ref gui.Style.List.ItemNormal); 42 | 43 | using (gui.StyleScope(ref gui.Style.Button, in style)) 44 | { 45 | if (gui.Button(label)) 46 | { 47 | selectedIndex = index; 48 | return true; 49 | } 50 | } 51 | 52 | return false; 53 | } 54 | 55 | public static bool ListItem(this ImGui gui, bool isSelected, ReadOnlySpan label) 56 | { 57 | ref readonly var style = ref (isSelected ? ref gui.Style.List.ItemSelected : ref gui.Style.List.ItemNormal); 58 | 59 | using (gui.StyleScope(ref gui.Style.Button, in style)) 60 | { 61 | if (gui.Button(label)) 62 | { 63 | return true; 64 | } 65 | } 66 | 67 | return false; 68 | } 69 | 70 | public static float GetEnclosingHeight(ImGui gui, float contentHeight) 71 | { 72 | return contentHeight + gui.Style.List.Padding.Vertical; 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImSeparator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Rendering; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static class ImSeparator 9 | { 10 | public static void Separator(this ImGui gui) 11 | { 12 | gui.AddSpacingIfLayoutFrameNotEmpty(); 13 | 14 | Separator(gui, gui.AddLayoutRect(gui.GetLayoutWidth(), gui.Style.Separator.Thickness)); 15 | } 16 | 17 | public static void Separator(this ImGui gui, ReadOnlySpan label) 18 | { 19 | gui.AddSpacingIfLayoutFrameNotEmpty(); 20 | 21 | Separator(gui, label, gui.AddLayoutRect(gui.GetLayoutWidth(), gui.Style.Layout.TextSize)); 22 | } 23 | 24 | public static void Separator(ImGui gui, ImRect rect) 25 | { 26 | if (gui.Canvas.Cull(rect)) 27 | { 28 | return; 29 | } 30 | 31 | var p0 = rect.LeftCenter; 32 | var p1 = rect.RightCenter; 33 | 34 | gui.Canvas.Line(p0, p1, gui.Style.Separator.Color, gui.Style.Separator.Thickness); 35 | } 36 | 37 | public static void Separator(ImGui gui, ReadOnlySpan label, ImRect rect) 38 | { 39 | if (gui.Canvas.Cull(rect)) 40 | { 41 | return; 42 | } 43 | 44 | var fontSize = Mathf.Min(gui.Style.Layout.TextSize, gui.TextDrawer.GetFontSizeFromLineHeight(rect.H)); 45 | var textSettings = new ImTextSettings(fontSize, gui.Style.Separator.TextAlignment, overflow: gui.Style.Separator.TextOverflow); 46 | var textRectSize = gui.MeasureTextSize(label, in textSettings, rect.Size); 47 | var start = Mathf.Max(rect.X, rect.X + (rect.W - textRectSize.x) * gui.Style.Separator.TextAlignment.X); 48 | var end = Mathf.Min(start + textRectSize.x, rect.Right); 49 | var textRect = new ImRect(start, rect.Y, end - start, rect.H); 50 | 51 | var p0 = rect.LeftCenter; 52 | var p1 = new Vector2(start - gui.Style.Separator.TextMargin.Left, rect.Center.y); 53 | var p2 = new Vector2(end + gui.Style.Separator.TextMargin.Right, rect.Center.y); 54 | var p3 = rect.RightCenter; 55 | 56 | if (p0.x < p1.x) 57 | { 58 | gui.Canvas.Line(p0, p1, gui.Style.Separator.Color, gui.Style.Separator.Thickness); 59 | } 60 | 61 | if (p2.x < p3.x) 62 | { 63 | gui.Canvas.Line(p2, p3, gui.Style.Separator.Color, gui.Style.Separator.Thickness); 64 | } 65 | 66 | gui.Text(label, textSettings, gui.Style.Separator.TextColor, textRect); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImGrid.cs: -------------------------------------------------------------------------------- 1 | using Imui.Core; 2 | using UnityEngine; 3 | 4 | namespace Imui.Controls 5 | { 6 | public struct ImGridState 7 | { 8 | public Vector2 Origin; 9 | public Vector2 CellSize; 10 | public Vector2 Spacing; 11 | public int Columns; 12 | public int X; 13 | public int Y; 14 | } 15 | 16 | public static class ImGrid 17 | { 18 | public static ImGridState BeginGrid(this ImGui gui, int columns, float cellHeight = 0) 19 | { 20 | var width = gui.GetLayoutWidth(); 21 | var spacing = GetDefaultSpacing(gui); 22 | var cellWidth = Mathf.Floor((width + spacing.x) / columns - spacing.x); 23 | cellHeight = cellHeight <= 0 ? cellWidth : cellHeight; 24 | 25 | return BeginGrid(gui, new Vector2(cellWidth, cellHeight), spacing); 26 | } 27 | 28 | public static ImGridState BeginGrid(this ImGui gui, Vector2 cellSize) 29 | { 30 | return BeginGrid(gui, cellSize, GetDefaultSpacing(gui)); 31 | } 32 | 33 | public static ImGridState BeginGrid(this ImGui gui, Vector2 cellSize, Vector2 spacing) 34 | { 35 | ref readonly var frame = ref gui.Layout.GetFrame(); 36 | 37 | var width = gui.Layout.GetAvailableWidth(); 38 | var columns = Mathf.Max(1, (width + spacing.x) / (cellSize.x + spacing.x)); 39 | var state = new ImGridState() 40 | { 41 | Origin = ImLayout.GetNextPosition(in frame, 0), 42 | CellSize = cellSize, 43 | Columns = (int)columns, 44 | Spacing = spacing 45 | }; 46 | 47 | return state; 48 | } 49 | 50 | public static void EndGrid(this ImGui gui, in ImGridState state) 51 | { 52 | var width = state.Columns * state.CellSize.x + (state.Columns - 1) * state.Spacing.x; 53 | var height = (state.Y + 1) * state.CellSize.y + state.Y * state.Spacing.y; 54 | gui.Layout.AddRect(width, height); 55 | } 56 | 57 | public static ImRect GridNextCell(this ImGui gui, ref ImGridState state) 58 | { 59 | if (state.X >= state.Columns) 60 | { 61 | state.X = 0; 62 | state.Y++; 63 | } 64 | 65 | var x = state.Origin.x + state.X * (state.CellSize.x + state.Spacing.x); 66 | var y = state.Origin.y - state.Y * (state.CellSize.y + state.Spacing.y); 67 | 68 | state.X++; 69 | 70 | return new ImRect(x, y - state.CellSize.y, state.CellSize.x, state.CellSize.y); 71 | } 72 | 73 | public static Vector2 GetDefaultSpacing(ImGui gui) 74 | { 75 | return new Vector2(gui.Style.Layout.Spacing, gui.Style.Layout.Spacing); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using Imui.Core; 4 | 5 | namespace Imui.Controls 6 | { 7 | public ref struct ImGroup 8 | { 9 | private const float HALF_BORDER = 0.5f; 10 | 11 | [Flags] 12 | public enum ItemFlag: byte 13 | { 14 | None = 0, 15 | AdjacentToLeft = 1 << 0, 16 | AdjacentToRight = 1 << 1 17 | } 18 | 19 | public readonly struct Item 20 | { 21 | public readonly ImRect Rect; 22 | public readonly ItemFlag Flags; 23 | 24 | public Item(ImRect rect, ItemFlag flags) 25 | { 26 | Rect = rect; 27 | Flags = flags; 28 | } 29 | } 30 | 31 | public readonly ImGui Gui; 32 | public readonly int Count; 33 | 34 | private int index; 35 | private ImRect rest; 36 | private float nextSize; 37 | 38 | public ImGroup(ImGui gui, ImRect rect, int count) 39 | { 40 | Gui = gui; 41 | Count = count; 42 | 43 | rest = rect; 44 | index = 0; 45 | nextSize = 0; 46 | } 47 | 48 | public void SetNextSize(float size) 49 | { 50 | nextSize = size; 51 | } 52 | 53 | public Item GetNext() 54 | { 55 | var item = nextSize > 0 ? GetNext(nextSize) : GetNext(rest.W / (Count - index)); 56 | nextSize = 0; 57 | return item; 58 | } 59 | 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | private Item GetNext(float size) 62 | { 63 | var rect = rest.TakeLeft(size, out rest); 64 | var flags = ItemFlag.None; 65 | 66 | if (index < Count - 1) 67 | { 68 | rect.W += HALF_BORDER; 69 | flags |= ItemFlag.AdjacentToRight; 70 | } 71 | 72 | if (index > 0) 73 | { 74 | rect.X -= HALF_BORDER; 75 | rect.W += HALF_BORDER; 76 | flags |= ItemFlag.AdjacentToLeft; 77 | } 78 | 79 | index++; 80 | 81 | return new Item(rect, flags); 82 | } 83 | } 84 | 85 | public static class ImGroupUtility 86 | { 87 | public static void Apply(this ref ImRectRadius radius, ImGroup.ItemFlag flags) 88 | { 89 | if ((flags & ImGroup.ItemFlag.AdjacentToLeft) != 0) 90 | { 91 | radius.TopLeft = 0.0f; 92 | radius.BottomLeft = 0.0f; 93 | } 94 | 95 | if ((flags & ImGroup.ItemFlag.AdjacentToRight) != 0) 96 | { 97 | radius.TopRight = 0.0f; 98 | radius.BottomRight = 0.0f; 99 | } 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImDynamicRenderTexture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | using UnityEngine.Rendering; 4 | 5 | namespace Imui.IO.Utility 6 | { 7 | public class ImDynamicRenderTexture: IDisposable 8 | { 9 | private const int RES_MIN = 32; 10 | private const int RES_MAX = 4096; 11 | 12 | public RenderTexture Texture { get; private set; } 13 | 14 | private RenderTexture prevTexture; 15 | private bool disposed; 16 | 17 | public Vector2Int SetupRenderTarget(CommandBuffer cmd, Vector2Int requestedSize, out bool textureChanged) 18 | { 19 | AssertDisposed(); 20 | 21 | textureChanged = SetupTexture(requestedSize, 1.0f, out var targetSize); 22 | 23 | cmd.Clear(); 24 | cmd.SetRenderTarget(Texture); 25 | cmd.ClearRenderTarget(true, true, Color.clear); 26 | 27 | return targetSize; 28 | } 29 | 30 | private bool SetupTexture(Vector2Int size, float scale, out Vector2Int targetSize) 31 | { 32 | AssertDisposed(); 33 | ReleasePrevTexture(); 34 | 35 | var w = Mathf.Clamp((int)(size.x * scale), RES_MIN, RES_MAX); 36 | var h = Mathf.Clamp((int)(size.y * scale), RES_MIN, RES_MAX); 37 | 38 | targetSize = new Vector2Int(w, h); 39 | 40 | if (w == 0 || h == 0) 41 | { 42 | return false; 43 | } 44 | 45 | if (Texture && Texture.IsCreated() && Texture.width == w && Texture.height == h) 46 | { 47 | return false; 48 | } 49 | 50 | if (Texture) 51 | { 52 | if (!prevTexture) 53 | { 54 | prevTexture = Texture; 55 | Texture = null; 56 | } 57 | else 58 | { 59 | ReleaseActiveTexture(); 60 | } 61 | } 62 | 63 | var desc = new RenderTextureDescriptor(w, h, RenderTextureFormat.ARGB32, 0, 0, RenderTextureReadWrite.Linear); 64 | 65 | Texture = new RenderTexture(desc) 66 | { 67 | name = "ImuiRenderBuffer" 68 | }; 69 | 70 | return Texture.Create(); 71 | } 72 | 73 | private void ReleasePrevTexture() 74 | { 75 | if (prevTexture) 76 | { 77 | prevTexture.Release(); 78 | prevTexture = null; 79 | } 80 | } 81 | 82 | private void ReleaseActiveTexture() 83 | { 84 | if (Texture) 85 | { 86 | Texture.Release(); 87 | Texture = null; 88 | } 89 | } 90 | 91 | #if UNITY_2022_2_OR_NEWER 92 | [HideInCallstack] 93 | #endif 94 | private void AssertDisposed() 95 | { 96 | if (disposed) 97 | { 98 | throw new ObjectDisposedException(nameof(ImDynamicRenderTexture)); 99 | } 100 | } 101 | 102 | public void Dispose() 103 | { 104 | if (disposed) 105 | { 106 | return; 107 | } 108 | 109 | ReleasePrevTexture(); 110 | ReleaseActiveTexture(); 111 | disposed = true; 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImDynamicArray.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Imui.Utility 4 | { 5 | internal struct ImDynamicArray 6 | { 7 | public int Count; 8 | public T[] Array; 9 | 10 | public ImDynamicArray(int capacity) 11 | { 12 | Array = new T[capacity]; 13 | Count = 0; 14 | } 15 | 16 | public bool RemoveAtFast(int index) 17 | { 18 | if (index < 0 || index >= Count) 19 | { 20 | throw new IndexOutOfRangeException($"{index} out of range, count: {Count}"); 21 | } 22 | 23 | Array[index] = Array[Count - 1]; 24 | Count--; 25 | return true; 26 | } 27 | 28 | public void RemoveAt(int index) 29 | { 30 | if (index < 0 || index >= Count) 31 | { 32 | throw new IndexOutOfRangeException($"{index} out of range, count: {Count}"); 33 | } 34 | 35 | System.Array.Copy(Array, index + 1, Array, index, --Count - index); 36 | } 37 | 38 | public void Add(T value) 39 | { 40 | EnsureCapacity(Count + 1); 41 | Array[Count++] = value; 42 | } 43 | 44 | public void Push(in T value) 45 | { 46 | EnsureCapacity(Count + 1); 47 | Array[Count++] = value; 48 | } 49 | 50 | public bool TryPop(out T value) 51 | { 52 | if (Count > 0) 53 | { 54 | value = Pop(); 55 | return true; 56 | } 57 | 58 | value = default; 59 | return false; 60 | } 61 | 62 | public T Pop() 63 | { 64 | ImAssert.IsTrue(Count > 0, "Count > 0"); 65 | 66 | return Array[--Count]; 67 | } 68 | 69 | public T TryPeek(T @default = default) 70 | { 71 | if (Count == 0) 72 | { 73 | return @default; 74 | } 75 | 76 | return Peek(); 77 | } 78 | 79 | public bool TryPeek(out T value) 80 | { 81 | if (Count == 0) 82 | { 83 | value = default; 84 | return false; 85 | } 86 | 87 | value = Peek(); 88 | return true; 89 | } 90 | 91 | public ref T Peek() 92 | { 93 | ImAssert.IsTrue(Count > 0, "Count > 0"); 94 | 95 | return ref Array[Count - 1]; 96 | } 97 | 98 | public void Clear(bool zero) 99 | { 100 | if (zero) 101 | { 102 | for (int i = 0; i < Count; ++i) 103 | { 104 | Array[i] = default; 105 | } 106 | } 107 | 108 | Count = 0; 109 | } 110 | 111 | public static implicit operator ReadOnlySpan(ImDynamicArray array) 112 | { 113 | return ((ReadOnlySpan)array.Array)[..array.Count]; 114 | } 115 | 116 | private void EnsureCapacity(int count) 117 | { 118 | if (count <= Array.Length) 119 | { 120 | return; 121 | } 122 | 123 | var newLength = Array.Length * 2; 124 | 125 | while (newLength < count) 126 | { 127 | newLength *= 2; 128 | } 129 | 130 | System.Array.Resize(ref Array, newLength); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_default.shader: -------------------------------------------------------------------------------- 1 | Shader "Hidden/Imui/Default" 2 | { 3 | Properties 4 | { 5 | [PerRendererData] _MainTex("Main Texture", 2D) = "white" {} 6 | [PerRendererData] _FontTex("Font Texture", 2D) = "white" {} 7 | [PerRendererData] _MaskEnable("Enable Masking", int) = 0 8 | [PerRendererData] _MaskRect("Mask Rect", Vector) = (0, 0, 0, 0) 9 | [PerRendererData] _MaskCornerRadius("Mask Corner Radius", float) = 0 10 | } 11 | 12 | SubShader 13 | { 14 | Tags { "RenderType" = "Transparent" } 15 | Blend One OneMinusSrcAlpha 16 | ZTest LEqual 17 | ZWrite On 18 | Cull Back 19 | 20 | Pass 21 | { 22 | CGPROGRAM 23 | 24 | #pragma vertex vert 25 | #pragma fragment frag 26 | #pragma multi_compile_local __ SDF_TEXT 27 | 28 | struct appdata 29 | { 30 | float2 vertex : POSITION; 31 | float4 color : COLOR; 32 | float2 uv : TEXCOORD0; 33 | float atlas : TEXCOORD1; 34 | }; 35 | 36 | struct v2f 37 | { 38 | float2 uv : TEXCOORD0; 39 | float atlas : TEXCOORD1; 40 | float4 vertex : SV_POSITION; 41 | float4 color : COLOR; 42 | }; 43 | 44 | sampler2D _MainTex; 45 | sampler2D _FontTex; 46 | 47 | float4x4 _VP; 48 | 49 | bool _MaskEnable; 50 | float4 _MaskRect; 51 | float _MaskCornerRadius; 52 | float _InvColorMul; 53 | 54 | // simplified signed distance round box from here: https://iquilezles.org/articles/distfunctions2d/ 55 | float sdf_round_box(in float2 p, in float2 s, in float r) 56 | { 57 | float2 q = abs(p) - s + r; 58 | return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; 59 | } 60 | 61 | v2f vert(appdata data) 62 | { 63 | v2f o; 64 | o.vertex = mul(_VP, float4(float3(data.vertex, 0.0), 1.0)); 65 | o.color = data.color; 66 | o.uv = data.uv; 67 | o.atlas = data.atlas; 68 | return o; 69 | } 70 | 71 | fixed4 frag(const v2f i) : SV_Target 72 | { 73 | #if SDF_TEXT 74 | float dist = (0.5 - tex2D(_FontTex, i.uv.xy).a); 75 | 76 | // sdf distance per pixel (gradient vector) 77 | float2 ddist = float2(ddx(dist), ddy(dist)); 78 | 79 | // distance to edge in pixels (scalar) 80 | float pixelDist = dist / length(ddist); 81 | 82 | fixed4 colFont = fixed4(1, 1, 1, saturate(0.5 - pixelDist)); 83 | #else 84 | fixed4 colFont = fixed4(1, 1, 1, tex2D(_FontTex, i.uv.xy).a); 85 | #endif 86 | 87 | fixed4 col = lerp(tex2D(_MainTex, i.uv.xy), colFont, i.atlas); 88 | col.a *= _MaskEnable 89 | ? 1 - saturate(sdf_round_box(i.vertex.xy - _MaskRect.xy, _MaskRect.zw, _MaskCornerRadius) * 2 + 1) 90 | : 1; 91 | col *= i.color; 92 | col.rgb *= col.a * (1 - _InvColorMul); 93 | 94 | return col; 95 | } 96 | 97 | ENDCG 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Utility/ImCircularBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace Imui.Utility 5 | { 6 | public struct ImCircularBuffer 7 | { 8 | public readonly int Capacity; 9 | 10 | public ref T this[Index index] 11 | { 12 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 13 | get => ref Array[(Head + (index.IsFromEnd ? Count - index.Value : index.Value)) % Capacity]; 14 | } 15 | 16 | public int Head; 17 | public int Count; 18 | public T[] Array; 19 | 20 | public ImCircularBuffer(int capacity) 21 | { 22 | Capacity = capacity; 23 | 24 | Head = 0; 25 | Count = 0; 26 | Array = new T[capacity]; 27 | } 28 | 29 | public ImCircularBuffer(T[] array) 30 | { 31 | if (array == null) 32 | { 33 | throw new ArgumentNullException(nameof(array)); 34 | } 35 | 36 | Capacity = array.Length; 37 | 38 | Head = 0; 39 | Count = 0; 40 | Array = array; 41 | } 42 | 43 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 44 | public ref T Get(int index) 45 | { 46 | return ref Array[(Head + index) % Capacity]; 47 | } 48 | 49 | 50 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 51 | public void Set(int index, T value) 52 | { 53 | Array[(Head + index) % Capacity] = value; 54 | } 55 | 56 | public void Clear() 57 | { 58 | Head = 0; 59 | Count = 0; 60 | } 61 | 62 | public int PushBack(T value) 63 | { 64 | Head = (Head - 1) % Capacity; 65 | 66 | if (Head < 0) 67 | { 68 | Head += Capacity; 69 | } 70 | 71 | Array[Head] = value; 72 | 73 | if (Count < Capacity) 74 | { 75 | Count++; 76 | } 77 | 78 | return Head; 79 | } 80 | 81 | public bool TryPopBack(out T value) 82 | { 83 | if (Count == 0) 84 | { 85 | value = default; 86 | return false; 87 | } 88 | 89 | value = Array[Head]; 90 | Head = (Head + 1) % Capacity; 91 | Count--; 92 | return true; 93 | } 94 | 95 | public int PushFront(T value) 96 | { 97 | var index = (Head + Count) % Capacity; 98 | 99 | Array[index] = value; 100 | 101 | if (Count == Capacity) 102 | { 103 | Head = (Head + 1) % Capacity; 104 | } 105 | else 106 | { 107 | Count++; 108 | } 109 | 110 | return index; 111 | } 112 | 113 | public bool TryPeekFront(out T value) 114 | { 115 | if (Count == 0) 116 | { 117 | value = default; 118 | return false; 119 | } 120 | 121 | value = Array[(Head + Count - 1) % Capacity]; 122 | return true; 123 | } 124 | 125 | public bool TryPopFront(out T value) 126 | { 127 | if (Count == 0) 128 | { 129 | value = default; 130 | return false; 131 | } 132 | 133 | value = Array[(Head + Count - 1) % Capacity]; 134 | Count--; 135 | return true; 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Utility/ImKeyboardCommandsHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.IO.Events; 3 | using UnityEngine; 4 | 5 | namespace Imui.IO.Utility 6 | { 7 | [Flags] 8 | public enum ImKeyboardCommandFlag: uint 9 | { 10 | None = 0, 11 | Select = 1 << 0, 12 | JumpWord = 1 << 1, 13 | SelectAll = 1 << 2, 14 | Copy = 1 << 3, 15 | Paste = 1 << 4, 16 | Cut = 1 << 5, 17 | JumpEnd = 1 << 6 18 | } 19 | 20 | public static class ImKeyboardCommandsHelper 21 | { 22 | public static bool TryGetCommand(ImKeyboardEvent evt, out ImKeyboardCommandFlag command) 23 | { 24 | return SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX 25 | ? TryGetCommandMacOS(evt, out command) 26 | : TryGetCommandGeneric(evt, out command); 27 | } 28 | 29 | public static bool TryGetCommandMacOS(ImKeyboardEvent evt, out ImKeyboardCommandFlag result) 30 | { 31 | result = ImKeyboardCommandFlag.None; 32 | 33 | var arrow = (int)evt.Key >= 273 && (int)evt.Key <= 276; 34 | var option = evt.Modifiers.HasFlag(EventModifiers.Alt); // option key 35 | var command = evt.Modifiers.HasFlag(EventModifiers.Command); 36 | var shift = evt.Modifiers.HasFlag(EventModifiers.Shift); 37 | 38 | if (arrow && command && !option) 39 | { 40 | result |= ImKeyboardCommandFlag.JumpEnd; 41 | } 42 | else if (arrow && !command && option) 43 | { 44 | result |= ImKeyboardCommandFlag.JumpWord; 45 | } 46 | 47 | if (arrow && shift) 48 | { 49 | result |= ImKeyboardCommandFlag.Select; 50 | } 51 | 52 | if (command && evt.Key == KeyCode.A) 53 | { 54 | result |= ImKeyboardCommandFlag.SelectAll; 55 | } 56 | 57 | if (command && evt.Key == KeyCode.C) 58 | { 59 | result |= ImKeyboardCommandFlag.Copy; 60 | } 61 | 62 | if (command && evt.Key == KeyCode.V) 63 | { 64 | result |= ImKeyboardCommandFlag.Paste; 65 | } 66 | 67 | if (command && evt.Key == KeyCode.X) 68 | { 69 | result |= ImKeyboardCommandFlag.Cut; 70 | } 71 | 72 | return result != ImKeyboardCommandFlag.None; 73 | } 74 | 75 | public static bool TryGetCommandGeneric(ImKeyboardEvent evt, out ImKeyboardCommandFlag command) 76 | { 77 | command = ImKeyboardCommandFlag.None; 78 | 79 | var arrow = (int)evt.Key >= 273 && (int)evt.Key <= 276; 80 | var control = evt.Modifiers.HasFlag(EventModifiers.Control); 81 | 82 | if (arrow && evt.Modifiers.HasFlag(EventModifiers.Shift)) 83 | { 84 | command |= ImKeyboardCommandFlag.Select; 85 | } 86 | 87 | if (arrow && control) 88 | { 89 | command |= ImKeyboardCommandFlag.JumpWord; 90 | } 91 | 92 | if (control && evt.Key == KeyCode.A) 93 | { 94 | command |= ImKeyboardCommandFlag.SelectAll; 95 | } 96 | 97 | if (control && evt.Key == KeyCode.C) 98 | { 99 | command |= ImKeyboardCommandFlag.Copy; 100 | } 101 | 102 | if (control && evt.Key == KeyCode.V) 103 | { 104 | command |= ImKeyboardCommandFlag.Paste; 105 | } 106 | 107 | if (control && evt.Key == KeyCode.X) 108 | { 109 | command |= ImKeyboardCommandFlag.Cut; 110 | } 111 | 112 | return command != ImKeyboardCommandFlag.None; 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImFoldout.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static class ImFoldout 9 | { 10 | private const float VERTICAL_ARROW_ASPECT_RATIO = 1.1547f; // ~ 2/sqrt(3) 11 | private const float HORIZONTAL_ARROW_ASPECT_RATIO = 1 / VERTICAL_ARROW_ASPECT_RATIO; 12 | 13 | public static bool BeginFoldout(this ImGui gui, ReadOnlySpan label, ImSize size = default, bool defaultOpen = false) 14 | { 15 | gui.AddSpacingIfLayoutFrameNotEmpty(); 16 | 17 | var id = gui.PushId(label); 18 | var rect = gui.AddSingleRowRect(size); 19 | 20 | ref var open = ref gui.Storage.Get(id, defaultOpen); 21 | DrawFoldout(gui, id, ref open, label, rect); 22 | 23 | if (!open) 24 | { 25 | gui.PopId(); 26 | return false; 27 | } 28 | 29 | return true; 30 | } 31 | 32 | public static void EndFoldout(this ImGui gui) 33 | { 34 | gui.PopId(); 35 | } 36 | 37 | public static void DrawFoldout(ImGui gui, uint id, ref bool open, ReadOnlySpan label, ImRect rect) 38 | { 39 | ref readonly var buttonStyle = ref gui.Style.Foldout.Button; 40 | 41 | var textSettings = ImButton.CreateTextSettings(gui, in buttonStyle); 42 | var arrowSize = gui.Style.Layout.TextSize; 43 | var contentRect = ImButton.CalculateContentRect(gui, rect); 44 | var arrowRect = contentRect.TakeLeft(arrowSize, gui.Style.Layout.InnerSpacing, out var labelRect).WithAspect(1.0f); 45 | 46 | if (gui.Button(id, rect, in buttonStyle, out var state)) 47 | { 48 | open = !open; 49 | } 50 | 51 | var frontColor = ImButton.GetStateFrontColor(in buttonStyle, state); 52 | 53 | if (open) 54 | { 55 | DrawArrowDown(gui.Canvas, arrowRect, frontColor, gui.Style.Foldout.ArrowScale); 56 | } 57 | else 58 | { 59 | DrawArrowRight(gui.Canvas, arrowRect, frontColor, gui.Style.Foldout.ArrowScale); 60 | } 61 | 62 | gui.Text(label, in textSettings, labelRect); 63 | } 64 | 65 | public static void DrawArrowRight(ImCanvas canvas, ImRect rect, Color32 color, float scale = 1.0f) 66 | { 67 | if (scale <= 0.0f) 68 | { 69 | return; 70 | } 71 | 72 | if (scale != 1.0f) 73 | { 74 | rect = rect.ScaleFromCenter(scale); 75 | } 76 | 77 | if (canvas.Cull(rect)) 78 | { 79 | return; 80 | } 81 | 82 | rect = rect.WithAspect(HORIZONTAL_ARROW_ASPECT_RATIO); 83 | 84 | Span points = stackalloc Vector2[3] 85 | { 86 | new Vector2(rect.X + rect.W, rect.Y + rect.H * 0.5f), new Vector2(rect.X, rect.Y + rect.H), new Vector2(rect.X, rect.Y) 87 | }; 88 | 89 | canvas.ConvexFill(points, color); 90 | } 91 | 92 | public static void DrawArrowDown(ImCanvas canvas, ImRect rect, Color32 color, float scale = 1.0f) 93 | { 94 | if (scale <= 0.0f) 95 | { 96 | return; 97 | } 98 | 99 | if (scale != 1.0f) 100 | { 101 | rect = rect.ScaleFromCenter(scale); 102 | } 103 | 104 | if (canvas.Cull(rect)) 105 | { 106 | return; 107 | } 108 | 109 | rect = rect.WithAspect(VERTICAL_ARROW_ASPECT_RATIO); 110 | 111 | Span points = stackalloc Vector2[3] 112 | { 113 | new Vector2(rect.X + rect.W * 0.5f, rect.Y), new Vector2(rect.X + rect.W, rect.Y + rect.H), new Vector2(rect.X, rect.Y + rect.H), 114 | }; 115 | 116 | canvas.ConvexFill(points, color); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImColorEdit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static class ImColorEdit 9 | { 10 | public static ImRect AddRect(ImGui gui, ImSize size) 11 | { 12 | if (size.Mode is ImSizeMode.Auto or ImSizeMode.Fit) 13 | { 14 | var threeCharWidth = gui.TextDrawer.GetCharacterAdvance('9', gui.Style.Layout.TextSize) * 3; 15 | var compLetterWidth = gui.GetRowHeight() * 0.75f; 16 | var textWidth = threeCharWidth + gui.Style.Layout.InnerSpacing * 2 + compLetterWidth; 17 | var minWidth = textWidth * 5 + gui.Style.Layout.InnerSpacing * 4; 18 | var width = Mathf.Max(gui.GetLayoutWidth(), minWidth); 19 | 20 | return gui.Layout.AddRect(width, gui.GetRowHeight()); 21 | } 22 | 23 | return gui.AddSingleRowRect(size); 24 | } 25 | 26 | public static Color ColorEdit(this ImGui gui, Color color, ImSize size = default) 27 | { 28 | ColorEdit(gui, ref color, size); 29 | return color; 30 | } 31 | 32 | public static bool ColorEdit(this ImGui gui, ref Color color, ImSize size = default) 33 | { 34 | gui.AddSpacingIfLayoutFrameNotEmpty(); 35 | 36 | var id = gui.GetNextControlId(); 37 | var rect = AddRect(gui, size); 38 | 39 | return ColorEdit(gui, id, ref color, rect); 40 | } 41 | 42 | public static bool ColorEdit(this ImGui gui, uint id, ref Color color, ImRect rect) 43 | { 44 | gui.PushId(id); 45 | 46 | var rId = gui.GetNextControlId(); 47 | var gId = gui.GetNextControlId(); 48 | var bId = gui.GetNextControlId(); 49 | var aId = gui.GetNextControlId(); 50 | var cId = gui.GetNextControlId(); 51 | 52 | Span rects = stackalloc ImRect[5]; 53 | rect.SplitHorizontal(ref rects, rects.Length, gui.Style.Layout.Spacing); 54 | 55 | var changed = false; 56 | var col32 = (Color32)color; 57 | var align = gui.Style.TextEdit.Alignment.X; 58 | 59 | try 60 | { 61 | gui.Style.TextEdit.Alignment.X = 0.5f; 62 | 63 | changed |= ColorComponent(gui, rId, in rects[0], Color.red, 'R', ref col32.r); 64 | changed |= ColorComponent(gui, gId, in rects[1], Color.green, 'G', ref col32.g); 65 | changed |= ColorComponent(gui, bId, in rects[2], Color.blue, 'B', ref col32.b); 66 | changed |= ColorComponent(gui, aId, in rects[3], gui.Style.Text.Color, 'A', ref col32.a); 67 | 68 | if (changed) 69 | { 70 | color = col32; 71 | } 72 | } 73 | finally 74 | { 75 | gui.Style.TextEdit.Alignment.X = align; 76 | } 77 | 78 | changed |= gui.ColorPickerButton(cId, ref color, rects[4], ImColorButtonFlag.AlphaOnePreview); 79 | 80 | gui.PopId(); 81 | 82 | return changed; 83 | } 84 | 85 | private static unsafe bool ColorComponent(ImGui gui, uint id, in ImRect rect, Color32 color, char letter, ref byte value) 86 | { 87 | var group = new ImGroup(gui, rect, 2); 88 | group.SetNextSize(gui.GetRowHeight() * 0.75f); 89 | var letterItem = group.GetNext(); 90 | var textStyle = new ImTextSettings(gui.Style.Layout.TextSize * 0.75f, 0.5f, 0.5f); 91 | var textColor = Color32.Lerp(gui.Style.Text.Color, color, 0.25f); 92 | var componentText = new ReadOnlySpan(&letter, 1); 93 | var componentStyle = gui.Style.TextEdit.Normal.Box; 94 | 95 | componentStyle.BorderRadius.Apply(letterItem.Flags); 96 | 97 | gui.Box(letterItem.Rect, in componentStyle); 98 | gui.Text(componentText, textStyle, textColor, letterItem.Rect); 99 | 100 | return group.NumericEdit(id, ref value, flags: ImNumericEditFlag.Slider); 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | // ReSharper disable RedundantCast 5 | 6 | namespace Imui.Core 7 | { 8 | public static unsafe class ImHash 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public static uint Get(ReadOnlySpan name, uint seed) 12 | { 13 | fixed (void* ptr = name) 14 | { 15 | return Get(ptr, name.Length * 2, seed); 16 | } 17 | } 18 | 19 | public static uint Get(uint data, uint seed) => Get(&data, sizeof(uint), seed); 20 | public static uint Get(int data, uint seed) => Get(&data, sizeof(int), seed); 21 | 22 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 23 | public static uint Get(void* data, int length, uint seed) 24 | { 25 | return MurmurHash3.Hash32(new ReadOnlySpan(data, length), seed); 26 | } 27 | } 28 | 29 | internal static class MurmurHash3 30 | { 31 | // https://github.com/odinmillion/MurmurHash.Net 32 | // MIT License 33 | // 34 | // Copyright (c) 2019 Evgeny Yuryev 35 | // 36 | // Permission is hereby granted, free of charge, to any person obtaining a copy 37 | // of this software and associated documentation files (the "Software"), to deal 38 | // in the Software without restriction, including without limitation the rights 39 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 | // copies of the Software, and to permit persons to whom the Software is 41 | // furnished to do so, subject to the following conditions: 42 | // 43 | // The above copyright notice and this permission notice shall be included in all 44 | // copies or substantial portions of the Software. 45 | // 46 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 52 | // SOFTWARE. 53 | 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static uint Hash32(ReadOnlySpan bytes, uint seed) 56 | { 57 | var length = bytes.Length; 58 | var h1 = seed; 59 | var remainder = length & 3; 60 | var position = length - remainder; 61 | for (var start = 0; start < position; start += 4) 62 | h1 = (uint)((int)RotateLeft(h1 ^ RotateLeft(BitConverter.ToUInt32(bytes.Slice(start, 4)) * 3432918353U, 15) * 461845907U, 13) * 5 - 430675100); 63 | 64 | if (remainder > 0) 65 | { 66 | uint num = 0; 67 | switch (remainder) 68 | { 69 | case 1: 70 | num ^= (uint)bytes[position]; 71 | break; 72 | case 2: 73 | num ^= (uint)bytes[position + 1] << 8; 74 | goto case 1; 75 | case 3: 76 | num ^= (uint)bytes[position + 2] << 16; 77 | goto case 2; 78 | } 79 | 80 | h1 ^= RotateLeft(num * 3432918353U, 15) * 461845907U; 81 | } 82 | 83 | h1 = FMix(h1 ^ (uint)length); 84 | 85 | return h1; 86 | } 87 | 88 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 89 | private static uint RotateLeft(uint x, byte r) 90 | { 91 | return x << (int)r | x >> 32 - (int)r; 92 | } 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | private static uint FMix(uint h) 96 | { 97 | h = (uint)(((int)h ^ (int)(h >> 16)) * -2048144789); 98 | h = (uint)(((int)h ^ (int)(h >> 13)) * -1028477387); 99 | return h ^ h >> 16; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImMenuBar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public struct ImMenuBarState 9 | { 10 | public uint Selected; 11 | } 12 | 13 | public static class ImMenuBar 14 | { 15 | public static float GetMenuBarHeight(ImGui gui) => gui.GetRowHeight(); 16 | 17 | public static void BeginMenuBar(this ImGui gui) 18 | { 19 | var id = gui.GetNextControlId(); 20 | 21 | if (gui.WindowManager.IsDrawingWindow()) 22 | { 23 | var rect = gui.GetWindowMenuBarRect(); 24 | 25 | BeginMenuBar(gui, id, rect, gui.Canvas.GetOrder() + ImWindow.WINDOW_MENU_ORDER_OFFSET - 1); 26 | } 27 | else 28 | { 29 | var height = GetMenuBarHeight(gui); 30 | var rect = gui.AddLayoutRect(gui.GetLayoutWidth(), height); 31 | 32 | if (Mathf.Approximately(gui.Canvas.ScreenRect.Top, rect.Top)) 33 | { 34 | gui.Canvas.SafeAreaPadding.Top += height; 35 | } 36 | 37 | BeginMenuBar(gui, id, rect, gui.Canvas.GetOrder()); 38 | } 39 | } 40 | 41 | public static void BeginMenuBar(this ImGui gui, ImRect rect) 42 | { 43 | var id = gui.GetNextControlId(); 44 | 45 | BeginMenuBar(gui, id, rect, gui.Canvas.GetOrder()); 46 | } 47 | 48 | public static void BeginMenuBar(ImGui gui, uint id, ImRect rect, int order) 49 | { 50 | gui.PushId(id); 51 | gui.BeginScope(id); 52 | gui.Layout.Push(ImAxis.Horizontal, rect); 53 | gui.Canvas.PushOrder(order); 54 | 55 | gui.Box(rect, in gui.Style.MenuBar.Box); 56 | } 57 | 58 | public static void EndMenuBar(this ImGui gui) 59 | { 60 | gui.Canvas.PopOrder(); 61 | gui.Layout.Pop(); 62 | gui.EndScope(); 63 | gui.PopId(); 64 | } 65 | 66 | public static bool Button(ImGui gui, ReadOnlySpan label) 67 | { 68 | var id = gui.GetNextControlId(); 69 | 70 | return Button(gui, id, label, false, out _); 71 | } 72 | 73 | public static bool Button(ImGui gui, uint id, ReadOnlySpan label, bool isSelected, out ImRect rect) 74 | { 75 | var textSettings = new ImTextSettings(gui.Style.Layout.TextSize, gui.Style.MenuBar.ItemNormal.Alignment); 76 | var textWidth = gui.MeasureTextSize(label, in textSettings).x; 77 | 78 | rect = gui.AddLayoutRect(textWidth + gui.Style.MenuBar.ItemExtraWidth, gui.GetLayoutHeight()) 79 | .WithPadding(gui.Style.MenuBar.Box.BorderThickness); 80 | 81 | ref var buttonStyle = ref (isSelected ? ref gui.Style.MenuBar.ItemActive : ref gui.Style.MenuBar.ItemNormal); 82 | using (gui.StyleScope(ref gui.Style.Button, in buttonStyle)) 83 | { 84 | return gui.Button(id, label, rect); 85 | } 86 | } 87 | 88 | public static bool BeginItem(ImGui gui, ReadOnlySpan label, ImMenuFlag flags = ImMenuFlag.None) 89 | { 90 | ref var barState = ref gui.GetCurrentScope(); 91 | 92 | var id = gui.PushId(label); 93 | var clicked = Button(gui, id, label, barState.Selected == id, out var rect); 94 | var source = rect.BottomLeft; 95 | 96 | if (barState.Selected != 0 && gui.IsControlHovered(id)) 97 | { 98 | barState.Selected = id; 99 | } 100 | 101 | if (clicked) 102 | { 103 | barState.Selected = barState.Selected == id ? 0 : id; 104 | } 105 | 106 | var open = barState.Selected == id; 107 | 108 | if (barState.Selected != default) 109 | { 110 | gui.BeginPopup(); 111 | gui.RegisterControl(id, rect); 112 | gui.EndPopup(); 113 | } 114 | 115 | if (!open) 116 | { 117 | gui.PopId(); 118 | return false; 119 | } 120 | 121 | gui.BeginMenuPopup(label, ref open, source, flags: flags); 122 | 123 | if (!open && barState.Selected == id) 124 | { 125 | barState.Selected = default; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | public static void EndItem(ImGui gui) 132 | { 133 | gui.EndMenuPopup(); 134 | gui.PopId(); 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /Editor/Icons/ImuiUnityGUIBackend.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7a2323d217d4244ee836766d2172a8ab 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 0 41 | wrapV: 0 42 | wrapW: 0 43 | nPOTScale: 1 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 0 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 0 56 | spriteTessellationDetail: -1 57 | textureType: 0 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 3 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 3 84 | buildTarget: WebGL 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 3 97 | buildTarget: Standalone 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | - serializedVersion: 3 110 | buildTarget: iPhone 111 | maxTextureSize: 2048 112 | resizeAlgorithm: 0 113 | textureFormat: -1 114 | textureCompression: 1 115 | compressionQuality: 50 116 | crunchedCompression: 0 117 | allowsAlphaSplitting: 0 118 | overridden: 0 119 | ignorePlatformSupport: 0 120 | androidETC2FallbackOverride: 0 121 | forceMaximumCompressionQuality_BC6H_BC7: 0 122 | - serializedVersion: 3 123 | buildTarget: Android 124 | maxTextureSize: 2048 125 | resizeAlgorithm: 0 126 | textureFormat: -1 127 | textureCompression: 1 128 | compressionQuality: 50 129 | crunchedCompression: 0 130 | allowsAlphaSplitting: 0 131 | overridden: 0 132 | ignorePlatformSupport: 0 133 | androidETC2FallbackOverride: 0 134 | forceMaximumCompressionQuality_BC6H_BC7: 0 135 | - serializedVersion: 3 136 | buildTarget: Server 137 | maxTextureSize: 2048 138 | resizeAlgorithm: 0 139 | textureFormat: -1 140 | textureCompression: 1 141 | compressionQuality: 50 142 | crunchedCompression: 0 143 | allowsAlphaSplitting: 0 144 | overridden: 0 145 | ignorePlatformSupport: 0 146 | androidETC2FallbackOverride: 0 147 | forceMaximumCompressionQuality_BC6H_BC7: 0 148 | spriteSheet: 149 | serializedVersion: 2 150 | sprites: [] 151 | outline: [] 152 | physicsShape: [] 153 | bones: [] 154 | spriteID: 155 | internalID: 0 156 | vertices: [] 157 | indices: 158 | edges: [] 159 | weights: [] 160 | secondaryTextures: [] 161 | nameFileIdTable: {} 162 | mipmapLimitGroupName: 163 | pSDRemoveMatte: 0 164 | userData: 165 | assetBundleName: 166 | assetBundleVariant: 167 | -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/Utility/ImLayoutUtility.cs: -------------------------------------------------------------------------------- 1 | using Imui.Core; 2 | using UnityEngine; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace Imui.Controls 6 | { 7 | public static class ImLayoutUtility 8 | { 9 | public static ImRect AddSingleRowRect(this ImGui gui, ImSize size, float minWidth = 0) 10 | { 11 | return size.Mode switch 12 | { 13 | ImSizeMode.Fixed => gui.Layout.AddRect(size.Width, size.Height), 14 | _ => gui.Layout.AddRect(Mathf.Max(minWidth, gui.Layout.GetAvailableWidth()), gui.GetRowHeight()) 15 | }; 16 | } 17 | 18 | public static float GetRowHeight(this ImGui gui) 19 | { 20 | return gui.TextDrawer.GetLineHeightFromFontSize(gui.Style.Layout.TextSize) + gui.Style.Layout.ExtraRowHeight; 21 | } 22 | 23 | public static float GetTextLineHeight(this ImGui gui) 24 | { 25 | return gui.TextDrawer.GetLineHeightFromFontSize(gui.Style.Layout.TextSize); 26 | } 27 | 28 | public static float GetRowsHeightWithSpacing(this ImGui gui, int rows) 29 | { 30 | return Mathf.Max(0, gui.GetRowHeight() * rows + gui.Style.Layout.Spacing * (rows - 1)); 31 | } 32 | 33 | public static void AddSpacingIfLayoutFrameNotEmpty(this ImGui gui) 34 | { 35 | if (!IsLayoutEmpty(gui)) 36 | { 37 | gui.AddSpacing(); 38 | } 39 | } 40 | 41 | public static bool IsLayoutEmpty(this ImGui gui) 42 | { 43 | ref readonly var frame = ref gui.Layout.GetFrame(); 44 | return frame.Size.x == 0 && frame.Size.y == 0; 45 | } 46 | 47 | public static void AddSpacing(this ImGui gui) 48 | { 49 | gui.Layout.AddSpace(gui.Style.Layout.Spacing); 50 | } 51 | 52 | public static void AddSpacing(this ImGui gui, float space) 53 | { 54 | gui.Layout.AddSpace(space); 55 | } 56 | 57 | public static void BeginIndent(this ImGui gui) 58 | { 59 | gui.Layout.AddIndent(gui.Style.Layout.Indent); 60 | } 61 | 62 | public static void EndIndent(this ImGui gui) 63 | { 64 | gui.Layout.AddIndent(-gui.Style.Layout.Indent); 65 | } 66 | 67 | public static Vector2 GetLayoutSize(this ImGui gui) 68 | { 69 | return gui.Layout.GetAvailableSize(); 70 | } 71 | 72 | public static float GetLayoutWidth(this ImGui gui) 73 | { 74 | return gui.Layout.GetAvailableWidth(); 75 | } 76 | 77 | public static float GetLayoutHeight(this ImGui gui) 78 | { 79 | return gui.Layout.GetAvailableHeight(); 80 | } 81 | 82 | public static Vector2 GetLayoutPosition(this ImGui gui) 83 | { 84 | ref readonly var frame = ref gui.Layout.GetFrame(); 85 | 86 | return ImLayout.GetNextPosition(in frame, 0.0f); 87 | } 88 | 89 | public static ImRect AddLayoutRect(this ImGui gui, Vector2 size) 90 | { 91 | return gui.Layout.AddRect(size); 92 | } 93 | 94 | public static ImRect AddLayoutRect(this ImGui gui, float width, float height) 95 | { 96 | return gui.Layout.AddRect(width, height); 97 | } 98 | 99 | public static ImRect AddLayoutRectWithSpacing(this ImGui gui, Vector2 size) 100 | { 101 | gui.AddSpacingIfLayoutFrameNotEmpty(); 102 | 103 | return gui.Layout.AddRect(size); 104 | } 105 | 106 | public static ImRect AddLayoutRectWithSpacing(this ImGui gui, float width, float height) 107 | { 108 | gui.AddSpacingIfLayoutFrameNotEmpty(); 109 | 110 | return gui.Layout.AddRect(width, height); 111 | } 112 | 113 | public static void BeginVertical(this ImGui gui, float width = 0.0f, float height = 0.0f) 114 | { 115 | gui.Layout.Push(ImAxis.Vertical, width, height); 116 | } 117 | 118 | public static void BeginVertical(this ImGui gui, Vector2 size) 119 | { 120 | gui.Layout.Push(ImAxis.Vertical, size); 121 | } 122 | 123 | public static void EndVertical(this ImGui gui) 124 | { 125 | gui.Layout.Pop(); 126 | } 127 | 128 | public static void BeginHorizontal(this ImGui gui, float width = 0.0f, float height = 0.0f) 129 | { 130 | gui.Layout.Push(ImAxis.Horizontal, width, height); 131 | } 132 | 133 | public static void BeginHorizontal(this ImGui gui, Vector2 size) 134 | { 135 | gui.Layout.Push(ImAxis.Horizontal, size); 136 | } 137 | 138 | public static void EndHorizontal(this ImGui gui) 139 | { 140 | gui.Layout.Pop(); 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImCheckbox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static class ImCheckbox 9 | { 10 | public static ImRect AddRect(ImGui gui, ImSize size, ReadOnlySpan label = default) 11 | { 12 | switch (size.Mode) 13 | { 14 | case ImSizeMode.Fixed: 15 | case ImSizeMode.Fill: 16 | return gui.AddSingleRowRect(size); 17 | default: 18 | var boxSize = gui.GetRowHeight(); 19 | 20 | if (label.IsEmpty) 21 | { 22 | return gui.Layout.AddRect(boxSize, boxSize); 23 | } 24 | 25 | var textSettings = GetTextSettings(gui); 26 | var textSize = gui.MeasureTextSize(label, in textSettings); 27 | var width = boxSize + gui.Style.Layout.InnerSpacing + textSize.x; 28 | var height = Mathf.Max(boxSize, textSize.y); 29 | 30 | if (size.Mode != ImSizeMode.Fit && gui.Layout.Axis != ImAxis.Horizontal) 31 | { 32 | width = Mathf.Max(gui.GetLayoutWidth(), width); 33 | } 34 | 35 | return gui.Layout.AddRect(width, height); 36 | } 37 | } 38 | 39 | public static bool Checkbox(this ImGui gui, bool value, ReadOnlySpan label = default, ImSize size = default) 40 | { 41 | Checkbox(gui, ref value, label, size); 42 | return value; 43 | } 44 | 45 | public static bool Checkbox(this ImGui gui, ref bool value, ReadOnlySpan label = default, ImSize size = default) 46 | { 47 | gui.AddSpacingIfLayoutFrameNotEmpty(); 48 | 49 | var rect = AddRect(gui, size, label); 50 | return Checkbox(gui, ref value, label, rect); 51 | } 52 | 53 | public static bool Checkbox(this ImGui gui, bool value, ReadOnlySpan label, ImRect rect) 54 | { 55 | Checkbox(gui, ref value, label, rect); 56 | return value; 57 | } 58 | 59 | public static bool Checkbox(this ImGui gui, ref bool value, ReadOnlySpan label, ImRect rect) 60 | { 61 | var id = gui.GetNextControlId(); 62 | var boxSize = gui.Style.Layout.TextSize + gui.Style.Layout.ExtraRowHeight; 63 | var boxRect = rect.TakeLeft(boxSize, out var textRect).WithAspect(1.0f); 64 | var changed = Checkbox(gui, id, ref value, boxRect); 65 | 66 | if (label.IsEmpty) 67 | { 68 | return changed; 69 | } 70 | 71 | var textSettings = GetTextSettings(gui); 72 | 73 | textRect.X += gui.Style.Layout.InnerSpacing; 74 | textRect.W -= gui.Style.Layout.InnerSpacing; 75 | gui.Canvas.Text(label, gui.Style.Text.Color, textRect, textSettings); 76 | 77 | if (gui.InvisibleButton(id, rect, ImButtonFlag.ActOnPressMouse)) 78 | { 79 | value = !value; 80 | changed = true; 81 | } 82 | 83 | return changed; 84 | } 85 | 86 | public static bool Checkbox(this ImGui gui, uint id, ref bool value, ImRect rect) 87 | { 88 | ref readonly var style = ref (value ? ref gui.Style.Checkbox.Checked : ref gui.Style.Checkbox.Normal); 89 | 90 | var clicked = gui.Button(id, rect, in style, out var state); 91 | var frontColor = ImButton.GetStateFrontColor(in style, state); 92 | 93 | if (value) 94 | { 95 | DrawCheckmark(gui.Canvas, rect, frontColor, gui.Style.Checkbox.CheckmarkScale); 96 | } 97 | 98 | if (clicked) 99 | { 100 | value = !value; 101 | } 102 | 103 | return clicked; 104 | } 105 | 106 | public static void DrawCheckmark(ImCanvas canvas, ImRect rect, Color32 color, float scale = 1.0f) 107 | { 108 | if (scale == 0) 109 | { 110 | return; 111 | } 112 | 113 | if (scale != 1.0) 114 | { 115 | rect = rect.ScaleFromCenter(scale); 116 | } 117 | 118 | if (canvas.Cull(rect)) 119 | { 120 | return; 121 | } 122 | 123 | var thickness = rect.W * 0.2f; 124 | 125 | ReadOnlySpan path = stackalloc Vector2[3] 126 | { 127 | rect.GetPointAtNormalPosition(0.00f, 0.60f), rect.GetPointAtNormalPosition(0.35f, 0.15f), rect.GetPointAtNormalPosition(1.00f, 0.80f) 128 | }; 129 | 130 | canvas.LineMiter(path, color, false, thickness); 131 | } 132 | 133 | public static ImTextSettings GetTextSettings(ImGui gui) 134 | { 135 | return new ImTextSettings(gui.Style.Layout.TextSize, 0.0f, 0.5f); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImWindowManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Utility; 3 | using UnityEngine; 4 | 5 | namespace Imui.Core 6 | { 7 | [Flags] 8 | public enum ImWindowFlag: ulong 9 | { 10 | None = 0, 11 | NoResizing = 1 << 0, 12 | NoMoving = 1 << 1, 13 | NoTitleBar = 1 << 2, 14 | NoCloseButton = 1 << 3, 15 | HasMenuBar = 1 << 4, 16 | NoMovingAndResizing = NoMoving | NoResizing 17 | } 18 | 19 | public class ImWindowManager 20 | { 21 | private const int DRAWING_STACK_CAPACITY = 8; 22 | private const int WINDOWS_CAPACITY = 32; 23 | 24 | internal ImDynamicArray drawingStack = new(DRAWING_STACK_CAPACITY); 25 | internal ImDynamicArray windows = new(WINDOWS_CAPACITY); 26 | 27 | public ref ImWindowState BeginWindow(uint id, string title, ImRect initialRect, ImWindowFlag flags) 28 | { 29 | drawingStack.Push(id); 30 | 31 | var index = TryFindWindow(id); 32 | if (index >= 0) 33 | { 34 | ref var window = ref windows.Array[index]; 35 | 36 | var wasVisible = window.Visible; 37 | 38 | window.Visible = true; 39 | window.NextVisible = true; 40 | 41 | if (!wasVisible) 42 | { 43 | MoveToTop(index); 44 | drawingStack.Pop(); 45 | return ref BeginWindow(id, title, initialRect, flags); 46 | } 47 | 48 | window.Flags = flags; 49 | 50 | if ((flags & ImWindowFlag.NoMovingAndResizing) == ImWindowFlag.NoMovingAndResizing) 51 | { 52 | window.Rect = initialRect; 53 | } 54 | 55 | return ref window; 56 | } 57 | 58 | windows.Add(new ImWindowState 59 | { 60 | Id = id, 61 | Order = windows.Count, 62 | Title = title, 63 | Rect = initialRect, 64 | Flags = flags, 65 | Visible = true, 66 | NextVisible = true 67 | }); 68 | 69 | return ref windows.Array[windows.Count - 1]; 70 | } 71 | 72 | public uint EndWindow() 73 | { 74 | return drawingStack.Pop(); 75 | } 76 | 77 | public bool IsDrawingWindow() 78 | { 79 | return drawingStack.Count > 0; 80 | } 81 | 82 | public bool TryGetDrawingWindowId(out uint id) 83 | { 84 | if (drawingStack.Count == 0) 85 | { 86 | id = default; 87 | return false; 88 | } 89 | 90 | id = drawingStack.Peek(); 91 | return true; 92 | } 93 | 94 | public bool Raycast(float x, float y) 95 | { 96 | for (int i = 0; i < windows.Count; ++i) 97 | { 98 | ref var state = ref windows.Array[i]; 99 | 100 | if (state.Visible && state.Rect.Contains(x, y)) 101 | { 102 | return true; 103 | } 104 | } 105 | 106 | return false; 107 | } 108 | 109 | public ref ImWindowState GetWindowState(uint id) 110 | { 111 | return ref windows.Array[TryFindWindow(id)]; 112 | } 113 | 114 | public void RequestFocus(uint id) 115 | { 116 | var index = TryFindWindow(id); 117 | if (index < 0) 118 | { 119 | return; 120 | } 121 | 122 | MoveToTop(index); 123 | } 124 | 125 | internal void HandleFrameEnded() 126 | { 127 | for (int i = 0; i < windows.Count; ++i) 128 | { 129 | ref var state = ref windows.Array[i]; 130 | 131 | state.Visible = state.NextVisible; 132 | state.NextVisible = false; 133 | } 134 | } 135 | 136 | private void MoveToTop(int index) 137 | { 138 | var state = windows.Array[index]; 139 | windows.RemoveAt(index); 140 | windows.Add(state); 141 | 142 | for (int i = 0; i < windows.Count; ++i) 143 | { 144 | windows.Array[i].Order = i; 145 | } 146 | } 147 | 148 | internal int TryFindWindow(uint id) 149 | { 150 | for (int i = 0; i < windows.Count; ++i) 151 | { 152 | if (windows.Array[i].Id == id) 153 | { 154 | return i; 155 | } 156 | } 157 | 158 | return -1; 159 | } 160 | } 161 | 162 | public struct ImWindowState 163 | { 164 | public uint Id; 165 | public int Order; 166 | public string Title; 167 | public ImRect Rect; 168 | public ImWindowFlag Flags; 169 | public bool Visible; 170 | public bool NextVisible; 171 | } 172 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImColorButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | [Flags] 9 | public enum ImColorButtonFlag 10 | { 11 | None = 0, 12 | AlphaOnePreview = 1 << 0 13 | } 14 | 15 | public static class ImColorButton 16 | { 17 | public static bool ColorPickerButton(this ImGui gui, ref Color color, ImSize size = default, ImColorButtonFlag flags = ImColorButtonFlag.None) 18 | { 19 | gui.AddSpacingIfLayoutFrameNotEmpty(); 20 | 21 | var id = gui.GetNextControlId(); 22 | var rect = gui.AddSingleRowRect(size, gui.GetRowHeight()); 23 | 24 | return ColorPickerButton(gui, id, ref color, rect, flags); 25 | } 26 | 27 | public static bool ColorPickerButton(this ImGui gui, uint id, ref Color color, ImRect rect, ImColorButtonFlag flags = ImColorButtonFlag.None) 28 | { 29 | ref var open = ref gui.Storage.Get(id, false); 30 | 31 | if (ColorButton(gui, id, color, rect, flags)) 32 | { 33 | open = !open; 34 | } 35 | 36 | if (!open) 37 | { 38 | return false; 39 | } 40 | 41 | gui.PushId(id); 42 | gui.BeginPopup(); 43 | 44 | var pickerId = gui.GetNextControlId(); 45 | var pickerRect = FindColorPickerPopupRect(gui, rect); 46 | gui.Box(pickerRect, gui.Style.Tooltip.Box); 47 | var changed = gui.ColorPicker(pickerId, ref color, pickerRect.WithPadding(gui.Style.Tooltip.Padding)); 48 | 49 | gui.EndPopupWithCloseButton(out var close); 50 | gui.PopId(); 51 | 52 | if (close) 53 | { 54 | open = false; 55 | } 56 | 57 | return changed; 58 | } 59 | 60 | public static bool ColorButton(this ImGui gui, Color color, ImSize size = default, ImColorButtonFlag flags = ImColorButtonFlag.None) 61 | { 62 | gui.AddSpacingIfLayoutFrameNotEmpty(); 63 | 64 | var id = gui.GetNextControlId(); 65 | var rect = gui.AddSingleRowRect(size, gui.GetRowHeight()); 66 | 67 | return ColorButton(gui, id, color, rect, flags); 68 | } 69 | 70 | public static bool ColorButton(this ImGui gui, uint id, Color color, ImRect rect, ImColorButtonFlag flags = ImColorButtonFlag.None) 71 | { 72 | var clicked = gui.InvisibleButton(id, rect, out var state); 73 | 74 | if (gui.Canvas.Cull(rect)) 75 | { 76 | return clicked; 77 | } 78 | 79 | var boxStyle = new ImStyleBox 80 | { 81 | BackColor = color, 82 | FrontColor = default, 83 | BorderColor = ImButton.GetStateBorderColor(in gui.Style.Button, state), 84 | BorderThickness = gui.Style.Button.BorderThickness, 85 | }; 86 | 87 | DrawCheckerboardPattern(gui, rect); 88 | 89 | if ((flags & ImColorButtonFlag.AlphaOnePreview) != 0) 90 | { 91 | var leftBoxColor = color; 92 | leftBoxColor.a = 1.0f; 93 | 94 | gui.Canvas.Rect(rect.TakeLeft(rect.W / 2.0f), leftBoxColor); 95 | } 96 | 97 | gui.Box(rect, boxStyle); 98 | 99 | return clicked; 100 | } 101 | 102 | public static void DrawCheckerboardPattern(ImGui gui, ImRect rect) 103 | { 104 | void SetPatternAspect(float aspect) 105 | { 106 | var scaleOffset = ImCanvas.GetTexScaleOffsetFor(ImCanvasBuiltinTex.Checkerboard); 107 | scaleOffset.x *= aspect; 108 | 109 | gui.Canvas.SetTexScaleOffset(scaleOffset); 110 | } 111 | 112 | var count = Mathf.CeilToInt(rect.W / rect.H); 113 | var tmp = gui.Canvas.GetTexScaleOffset(); 114 | 115 | var color = (Color32)Color.white; 116 | var width = rect.W; 117 | 118 | while (count > 0) 119 | { 120 | var w = Mathf.Min(width, rect.H); 121 | var r = new ImRect(rect.X + (rect.W - width), rect.Y, w, rect.H); 122 | 123 | SetPatternAspect(w / rect.H); 124 | gui.Canvas.Rect(r, color); 125 | 126 | width -= w; 127 | count--; 128 | } 129 | 130 | gui.Canvas.SetTexScaleOffset(tmp); 131 | } 132 | 133 | public static ImRect FindColorPickerPopupRect(ImGui gui, ImRect buttonRect) 134 | { 135 | var width = Mathf.Max(buttonRect.W, gui.GetRowHeight() * 10) + gui.Style.Tooltip.Padding.Horizontal; 136 | var height = ImColorPicker.GetHeight(gui, width) + gui.Style.Tooltip.Padding.Vertical; 137 | 138 | var x = Mathf.Max(gui.Canvas.ScreenRect.X, Mathf.Min(buttonRect.X, buttonRect.Right - width)); 139 | var y = buttonRect.Y - height - gui.Style.Layout.Spacing; 140 | 141 | if (y < gui.Canvas.ScreenRect.Y) 142 | { 143 | y = buttonRect.Top + gui.Style.Layout.Spacing; 144 | } 145 | 146 | return new ImRect(x, y, width, height); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Rendering/ImMeshBuffer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using UnityEngine; 4 | 5 | namespace Imui.Rendering 6 | { 7 | public class ImMeshBuffer 8 | { 9 | public int VerticesCount; 10 | public int IndicesCount; 11 | public ImVertex[] Vertices; 12 | public int[] Indices; 13 | public ImMeshData[] Meshes; 14 | public int MeshesCount; 15 | 16 | public ImMeshBuffer(int meshesCapacity, int verticesCapacity, int indicesCapacity) 17 | { 18 | Vertices = new ImVertex[verticesCapacity]; 19 | Indices = new int[indicesCapacity]; 20 | Meshes = new ImMeshData[meshesCapacity]; 21 | 22 | Clear(); 23 | } 24 | 25 | public void Trim() 26 | { 27 | if (MeshesCount == 0) 28 | { 29 | return; 30 | } 31 | 32 | ref var meshData = ref Meshes[MeshesCount - 1]; 33 | while ((meshData.VerticesCount == 0 || meshData.IndicesCount == 0) && MeshesCount > 1) 34 | { 35 | meshData = ref Meshes[--MeshesCount - 1]; 36 | } 37 | } 38 | 39 | public void Sort() 40 | { 41 | var meshes = new Span(Meshes, 0, MeshesCount); 42 | var i = 1; 43 | while (i < meshes.Length) 44 | { 45 | var m = meshes[i]; 46 | var j = i - 1; 47 | while (j >= 0 && meshes[j].Order > m.Order) 48 | { 49 | meshes[j + 1] = meshes[j]; 50 | j -= 1; 51 | } 52 | 53 | meshes[j + 1] = m; 54 | ++i; 55 | } 56 | } 57 | 58 | public void Clear() 59 | { 60 | MeshesCount = 0; 61 | VerticesCount = 0; 62 | IndicesCount = 0; 63 | } 64 | 65 | public void NextMesh() 66 | { 67 | if (MeshesCount > 0) 68 | { 69 | ref var currentMesh = ref Meshes[MeshesCount - 1]; 70 | if (currentMesh.VerticesCount == 0 && currentMesh.IndicesCount == 0) 71 | { 72 | currentMesh.ClearOptions(); 73 | return; 74 | } 75 | } 76 | 77 | EnsureMeshesCapacity(MeshesCount + 1); 78 | 79 | ref var mesh = ref Meshes[MeshesCount++]; 80 | mesh.Clear(); 81 | mesh.IndicesOffset = IndicesCount; 82 | mesh.VerticesOffset = VerticesCount; 83 | } 84 | 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | public void EnsureMeshesCapacity(int size) 87 | { 88 | if (Meshes.Length < size) 89 | { 90 | Array.Resize(ref Meshes, Mathf.NextPowerOfTwo(size)); 91 | } 92 | } 93 | 94 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 95 | public void EnsureVerticesCapacity(int size) 96 | { 97 | if (Vertices.Length < size) 98 | { 99 | Array.Resize(ref Vertices, Mathf.NextPowerOfTwo(size)); 100 | } 101 | } 102 | 103 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 104 | public void EnsureIndicesCapacity(int size) 105 | { 106 | if (Indices.Length < size) 107 | { 108 | Array.Resize(ref Indices, Mathf.NextPowerOfTwo(size)); 109 | } 110 | } 111 | 112 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 113 | public void AddIndices(int count) 114 | { 115 | #if IMUI_VALIDATION 116 | ImAssert.IsFalse(MeshesCount == 0, "Empty meshes array"); 117 | 118 | var from = Meshes[MeshesCount - 1].IndicesOffset + Meshes[MeshesCount - 1].IndicesCount; 119 | var to = from + count; 120 | 121 | ImAssert.IsFalse(to > Indices.Length, "Indices array is too small"); 122 | 123 | for (int i = from; i < to; ++i) 124 | { 125 | ImAssert.IsTrue(Indices[i] >= 0 && Indices[i] < Vertices.Length, $"Invalid index {Indices[i]} at {i}"); 126 | } 127 | #endif 128 | 129 | IndicesCount += count; 130 | Meshes[MeshesCount - 1].IndicesCount += count; 131 | } 132 | 133 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 134 | public void AddVertices(int count) 135 | { 136 | #if IMUI_VALIDATION 137 | ImAssert.IsFalse(MeshesCount == 0, "Empty meshes array"); 138 | 139 | var from = Meshes[MeshesCount - 1].VerticesOffset + Meshes[MeshesCount - 1].VerticesCount; 140 | var to = from + count; 141 | 142 | ImAssert.IsFalse(to > Vertices.Length, "Vertices array is too small"); 143 | 144 | for (int i = from; i < to; ++i) 145 | { 146 | var v = Vertices[i]; 147 | if (float.IsNaN(v.Position.x) || float.IsInfinity(v.Position.x) || 148 | float.IsNaN(v.Position.y) || float.IsInfinity(v.Position.y)) 149 | { 150 | ImAssert.IsTrue(false, "Invalid vertex position, some of the components is either NaN of Infinity"); 151 | } 152 | } 153 | #endif 154 | 155 | VerticesCount += count; 156 | Meshes[MeshesCount - 1].VerticesCount += count; 157 | } 158 | } 159 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Examples/ImThemeEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Controls; 3 | using Imui.Core; 4 | using Imui.Rendering; 5 | using Imui.Style; 6 | 7 | namespace Imui.Examples 8 | { 9 | public static class ImThemeEditor 10 | { 11 | public struct LabeledScope: IDisposable 12 | { 13 | private ImGui gui; 14 | 15 | public LabeledScope(ImGui gui, ReadOnlySpan label) 16 | { 17 | this.gui = gui; 18 | 19 | gui.AddSpacingIfLayoutFrameNotEmpty(); 20 | gui.BeginHorizontal(); 21 | var rect = gui.AddLayoutRect(gui.GetLayoutWidth() * 0.4f, gui.GetRowHeight()); 22 | gui.Text(label, rect, overflow: ImTextOverflow.Ellipsis); 23 | gui.BeginVertical(); 24 | } 25 | 26 | public void Dispose() 27 | { 28 | gui.EndVertical(); 29 | gui.EndHorizontal(); 30 | } 31 | } 32 | 33 | public static bool DrawEditor(ImGui gui, ref ImTheme theme) 34 | { 35 | var changed = false; 36 | 37 | gui.Separator("Colors"); 38 | 39 | using (new LabeledScope(gui, nameof(theme.Foreground))) changed |= gui.ColorEdit(ref theme.Foreground); 40 | using (new LabeledScope(gui, nameof(theme.Background))) changed |= gui.ColorEdit(ref theme.Background); 41 | using (new LabeledScope(gui, nameof(theme.Accent))) changed |= gui.ColorEdit(ref theme.Accent); 42 | using (new LabeledScope(gui, nameof(theme.Control))) changed |= gui.ColorEdit(ref theme.Control); 43 | using (new LabeledScope(gui, nameof(theme.Contrast))) changed |= gui.Slider(ref theme.Contrast, -1.0f, +1.0f); 44 | using (new LabeledScope(gui, nameof(theme.BorderContrast))) changed |= gui.Slider(ref theme.BorderContrast, -1.0f, +2.0f); 45 | 46 | gui.Separator("Values"); 47 | 48 | using (new LabeledScope(gui, nameof(theme.TextSize))) changed |= gui.Slider(ref theme.TextSize, 4.0f, 128.0f); 49 | using (new LabeledScope(gui, nameof(theme.Spacing))) changed |= gui.Slider(ref theme.Spacing, 0.0f, 32.0f); 50 | using (new LabeledScope(gui, nameof(theme.InnerSpacing))) changed |= gui.Slider(ref theme.InnerSpacing, 0.0f, 32.0f); 51 | using (new LabeledScope(gui, nameof(theme.Indent))) changed |= gui.Slider(ref theme.Indent, 0.0f, 128.0f); 52 | using (new LabeledScope(gui, nameof(theme.ExtraRowHeight))) changed |= gui.Slider(ref theme.ExtraRowHeight, 0.0f, 128.0f); 53 | using (new LabeledScope(gui, nameof(theme.ScrollBarSize))) changed |= gui.Slider(ref theme.ScrollBarSize, 2.0f, 128.0f); 54 | using (new LabeledScope(gui, nameof(theme.WindowBorderRadius))) changed |= gui.Slider(ref theme.WindowBorderRadius, 0.0f, 32.0f); 55 | using (new LabeledScope(gui, nameof(theme.WindowBorderThickness))) changed |= gui.Slider(ref theme.WindowBorderThickness, 0.0f, 8.0f, step: 0.5f); 56 | using (new LabeledScope(gui, nameof(theme.BorderRadius))) changed |= gui.Slider(ref theme.BorderRadius, 0.0f, 16.0f); 57 | using (new LabeledScope(gui, nameof(theme.BorderThickness))) changed |= gui.Slider(ref theme.BorderThickness, 0.0f, 8.0f, step: 0.5f); 58 | using (new LabeledScope(gui, nameof(theme.ReadOnlyColorMultiplier))) changed |= gui.Slider(ref theme.ReadOnlyColorMultiplier, 0.0f, 8.0f); 59 | 60 | return changed; 61 | } 62 | 63 | public static string BuildCodeString(in ImTheme theme) 64 | { 65 | byte AsByte(float component) => (byte)(255 * component); 66 | 67 | return "new ImTheme()\n" + 68 | "{\n" + 69 | $" {nameof(theme.TextSize)} = {theme.TextSize:0.##}f,\n" + 70 | $" {nameof(theme.Spacing)} = {theme.Spacing:0.##}f,\n" + 71 | $" {nameof(theme.InnerSpacing)} = {theme.InnerSpacing:0.##}f,\n" + 72 | $" {nameof(theme.Indent)} = {theme.Indent:0.##}f,\n" + 73 | $" {nameof(theme.ExtraRowHeight)} = {theme.ExtraRowHeight:0.##}f,\n" + 74 | $" {nameof(theme.ScrollBarSize)} = {theme.ScrollBarSize:0.##}f,\n" + 75 | $" {nameof(theme.WindowBorderRadius)} = {theme.WindowBorderRadius:0.##}f,\n" + 76 | $" {nameof(theme.WindowBorderThickness)} = {theme.WindowBorderThickness:0.##}f,\n" + 77 | $" {nameof(theme.BorderRadius)} = {theme.BorderRadius:0.##}f,\n" + 78 | $" {nameof(theme.BorderThickness)} = {theme.BorderThickness:0.##}f,\n" + 79 | $" {nameof(theme.ReadOnlyColorMultiplier)} = {theme.ReadOnlyColorMultiplier:0.##}f,\n" + 80 | $" {nameof(theme.Background)} = new Color32({AsByte(theme.Background.r)}, {AsByte(theme.Background.g)}, {AsByte(theme.Background.b)}, {AsByte(theme.Background.a)}),\n" + 81 | $" {nameof(theme.Foreground)} = new Color32({AsByte(theme.Foreground.r)}, {AsByte(theme.Foreground.g)}, {AsByte(theme.Foreground.b)}, {AsByte(theme.Foreground.a)}),\n" + 82 | $" {nameof(theme.Accent)} = new Color32({AsByte(theme.Accent.r)}, {AsByte(theme.Accent.g)}, {AsByte(theme.Accent.b)}, {AsByte(theme.Accent.a)}),\n" + 83 | $" {nameof(theme.Control)} = new Color32({AsByte(theme.Control.r)}, {AsByte(theme.Control.g)}, {AsByte(theme.Control.b)}, {AsByte(theme.Control.a)}),\n" + 84 | $" {nameof(theme.Contrast)} = {theme.Contrast:0.##}f,\n" + 85 | $" {nameof(theme.BorderContrast)} = {theme.BorderContrast:0.##}f\n" + 86 | "};"; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Runtime/Resources/Imui/imui_ugui.shader: -------------------------------------------------------------------------------- 1 | // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt) 2 | // Default UI shader from 6000.2, modified to apply gamma correction for linear color space setup 3 | 4 | Shader "Hidden/Imui/UGUI" 5 | { 6 | Properties 7 | { 8 | [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {} 9 | _Color ("Tint", Color) = (1,1,1,1) 10 | 11 | _StencilComp ("Stencil Comparison", Float) = 8 12 | _Stencil ("Stencil ID", Float) = 0 13 | _StencilOp ("Stencil Operation", Float) = 0 14 | _StencilWriteMask ("Stencil Write Mask", Float) = 255 15 | _StencilReadMask ("Stencil Read Mask", Float) = 255 16 | 17 | _ColorMask ("Color Mask", Float) = 15 18 | 19 | [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0 20 | } 21 | 22 | SubShader 23 | { 24 | Tags 25 | { 26 | "Queue"="Transparent" 27 | "IgnoreProjector"="True" 28 | "RenderType"="Transparent" 29 | "PreviewType"="Plane" 30 | "CanUseSpriteAtlas"="True" 31 | } 32 | 33 | Stencil 34 | { 35 | Ref [_Stencil] 36 | Comp [_StencilComp] 37 | Pass [_StencilOp] 38 | ReadMask [_StencilReadMask] 39 | WriteMask [_StencilWriteMask] 40 | } 41 | 42 | Cull Off 43 | Lighting Off 44 | ZWrite Off 45 | ZTest [unity_GUIZTestMode] 46 | Blend One OneMinusSrcAlpha 47 | ColorMask [_ColorMask] 48 | 49 | Pass 50 | { 51 | Name "Default" 52 | CGPROGRAM 53 | #pragma vertex vert 54 | #pragma fragment frag 55 | #pragma target 2.0 56 | 57 | #include "UnityCG.cginc" 58 | #include "UnityUI.cginc" 59 | 60 | #pragma multi_compile_local _ UNITY_UI_CLIP_RECT 61 | #pragma multi_compile_local _ UNITY_UI_ALPHACLIP 62 | 63 | 64 | struct appdata_t 65 | { 66 | float4 vertex : POSITION; 67 | float4 color : COLOR; 68 | float2 texcoord : TEXCOORD0; 69 | UNITY_VERTEX_INPUT_INSTANCE_ID 70 | }; 71 | 72 | struct v2f 73 | { 74 | float4 vertex : SV_POSITION; 75 | fixed4 color : COLOR; 76 | float2 texcoord : TEXCOORD0; 77 | float4 worldPosition : TEXCOORD1; 78 | float4 mask : TEXCOORD2; 79 | UNITY_VERTEX_OUTPUT_STEREO 80 | }; 81 | 82 | sampler2D _MainTex; 83 | fixed4 _Color; 84 | fixed4 _TextureSampleAdd; 85 | float4 _ClipRect; 86 | float4 _MainTex_ST; 87 | float _UIMaskSoftnessX; 88 | float _UIMaskSoftnessY; 89 | int _UIVertexColorAlwaysGammaSpace; 90 | 91 | v2f vert(appdata_t v) 92 | { 93 | v2f OUT; 94 | UNITY_SETUP_INSTANCE_ID(v); 95 | UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 96 | float4 vPosition = UnityObjectToClipPos(v.vertex); 97 | OUT.worldPosition = v.vertex; 98 | OUT.vertex = vPosition; 99 | 100 | float2 pixelSize = vPosition.w; 101 | pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy)); 102 | 103 | float4 clampedRect = clamp(_ClipRect, -2e10, 2e10); 104 | float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy); 105 | OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex); 106 | OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy))); 107 | 108 | 109 | if (_UIVertexColorAlwaysGammaSpace) 110 | { 111 | if(!IsGammaSpace()) 112 | { 113 | v.color.rgb = UIGammaToLinear(v.color.rgb); 114 | } 115 | } 116 | 117 | OUT.color = v.color * _Color; 118 | return OUT; 119 | } 120 | 121 | fixed4 frag(v2f IN) : SV_Target 122 | { 123 | //Round up the alpha color coming from the interpolator (to 1.0/256.0 steps) 124 | //The incoming alpha could have numerical instability, which makes it very sensible to 125 | //HDR color transparency blend, when it blends with the world's texture. 126 | const half alphaPrecision = half(0xff); 127 | const half invAlphaPrecision = half(1.0/alphaPrecision); 128 | IN.color.a = round(IN.color.a * alphaPrecision)*invAlphaPrecision; 129 | 130 | half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd); 131 | 132 | #ifdef UNITY_UI_CLIP_RECT 133 | half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw); 134 | color.a *= m.x * m.y; 135 | #endif 136 | 137 | #ifdef UNITY_UI_ALPHACLIP 138 | clip (color.a - 0.001); 139 | #endif 140 | 141 | color.rgb *= color.a; 142 | 143 | // TODO (artem-s): should be the other way around, and themes should use linear colors 144 | if(!IsGammaSpace()) 145 | { 146 | color.rgb = GammaToLinearSpace(color.rgb); 147 | } 148 | 149 | return color; 150 | } 151 | ENDCG 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImRadiobox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using Imui.Utility; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static class ImRadio 9 | { 10 | public static TEnum Radio(this ImGui gui, TEnum value, bool bitMasks = true) where TEnum: struct, Enum 11 | { 12 | Radio(gui, ref value, bitMasks); 13 | return value; 14 | } 15 | 16 | public static bool Radio(this ImGui gui, ref TEnum value, bool bitMasks = true) where TEnum: struct, Enum 17 | { 18 | var changed = false; 19 | 20 | if (!ImEnumUtility.IsFlags || !bitMasks) 21 | { 22 | var underlyingValue = ImEnumUtility.ToValue(value); 23 | 24 | for (int i = 0; i < ImEnumUtility.Names.Length; ++i) 25 | { 26 | var name = ImEnumUtility.Names[i]; 27 | var val = ImEnumUtility.Values[i]; 28 | var selected = ImEnumUtility.ToValue(val) == underlyingValue; 29 | 30 | if (Radio(gui, ref selected, name) && selected) 31 | { 32 | value = val; 33 | changed = true; 34 | } 35 | } 36 | } 37 | else 38 | { 39 | var mask = ImEnumUtility.ToValue(value); 40 | 41 | for (int i = 0; i < ImEnumUtility.Names.Length; ++i) 42 | { 43 | var name = ImEnumUtility.Names[i]; 44 | var bit = ImEnumUtility.ToValue(ImEnumUtility.Values[i]); 45 | 46 | changed |= RadioEnumMask(gui, ref mask, bit, name); 47 | } 48 | 49 | value = mask.ToEnumType(); 50 | } 51 | 52 | return changed; 53 | } 54 | 55 | private static bool RadioEnumMask(this ImGui gui, 56 | ref ImEnumValue mask, 57 | ImEnumValue value, 58 | ReadOnlySpan label, 59 | ImSize size = default) where TEnum: struct, Enum 60 | { 61 | var selected = value == 0 ? mask == 0 : (mask & value) == value; 62 | var changed = Radio(gui, ref selected, label, size); 63 | 64 | if (!changed) 65 | { 66 | return false; 67 | } 68 | 69 | if (value == 0) 70 | { 71 | mask = 0; 72 | } 73 | else if (selected) 74 | { 75 | mask |= value; 76 | } 77 | else 78 | { 79 | mask &= ~value; 80 | } 81 | 82 | return true; 83 | } 84 | 85 | public static bool Radio(this ImGui gui, bool value, ReadOnlySpan label = default, ImSize size = default) 86 | { 87 | Radio(gui, ref value, label, size); 88 | return value; 89 | } 90 | 91 | public static bool Radio(this ImGui gui, ref bool value, ReadOnlySpan label = default, ImSize size = default) 92 | { 93 | gui.AddSpacingIfLayoutFrameNotEmpty(); 94 | 95 | var rect = ImCheckbox.AddRect(gui, size, label); 96 | return Radio(gui, ref value, label, rect); 97 | } 98 | 99 | public static bool Radio(this ImGui gui, bool value, ReadOnlySpan label, ImRect rect) 100 | { 101 | Radio(gui, ref value, label, rect); 102 | return value; 103 | } 104 | 105 | public static bool Radio(this ImGui gui, ref bool value, ReadOnlySpan label, ImRect rect) 106 | { 107 | var id = gui.GetNextControlId(); 108 | var boxSize = gui.Style.Layout.TextSize + gui.Style.Layout.ExtraRowHeight; 109 | var boxRect = rect.TakeLeft(boxSize, out var textRect).WithAspect(1.0f); 110 | var changed = Radio(gui, id, ref value, boxRect); 111 | 112 | if (label.IsEmpty) 113 | { 114 | return changed; 115 | } 116 | 117 | var textSettings = GetTextSettings(gui); 118 | 119 | textRect.X += gui.Style.Layout.InnerSpacing; 120 | textRect.W -= gui.Style.Layout.InnerSpacing; 121 | gui.Canvas.Text(label, gui.Style.Text.Color, textRect, textSettings); 122 | 123 | if (gui.InvisibleButton(id, rect, ImButtonFlag.ActOnPressMouse)) 124 | { 125 | value = !value; 126 | changed = true; 127 | } 128 | 129 | return changed; 130 | } 131 | 132 | public static bool Radio(this ImGui gui, uint id, ref bool value, ImRect rect) 133 | { 134 | ref readonly var style = ref (value ? ref gui.Style.Radiobox.Checked : ref gui.Style.Radiobox.Normal); 135 | 136 | var clicked = gui.Button(id, rect, in style, out var state); 137 | var frontColor = ImButton.GetStateFrontColor(in style, state); 138 | 139 | if (value) 140 | { 141 | var circleRect = rect.ScaleFromCenter(gui.Style.Radiobox.KnobScale); 142 | gui.Canvas.Ellipse(circleRect, frontColor); 143 | } 144 | 145 | if (clicked) 146 | { 147 | value = !value; 148 | } 149 | 150 | return clicked; 151 | } 152 | 153 | public static ImTextSettings GetTextSettings(ImGui gui) 154 | { 155 | return new ImTextSettings(gui.Style.Layout.TextSize, 0.0f, 0.5f); 156 | } 157 | } 158 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Rendering; 4 | using UnityEngine; 5 | using UnityEngine.Rendering; 6 | using UnityEngine.U2D; 7 | 8 | namespace Imui.Controls 9 | { 10 | public static class ImImage 11 | { 12 | private static readonly Color32 White = new Color32(255, 255, 255, 255); 13 | 14 | public static ImRect AddRect(ImGui gui, Texture texture, ImSize size) 15 | { 16 | return size.Mode switch 17 | { 18 | ImSizeMode.Fixed => gui.Layout.AddRect(size.Width, size.Height), 19 | _ => gui.Layout.AddRect(texture.width, texture.height) 20 | }; 21 | } 22 | 23 | public static void Image(this ImGui gui, Texture texture, ImSize size = default, bool preserveAspect = false) 24 | { 25 | Image(gui, texture, AddRect(gui, texture, size), preserveAspect); 26 | } 27 | 28 | public static void Image(this ImGui gui, Texture texture, ImRect rect, bool preserveAspect = false) 29 | { 30 | if (gui.Canvas.Cull(rect) || !texture) 31 | { 32 | return; 33 | } 34 | 35 | if (preserveAspect) 36 | { 37 | rect = rect.WithAspect(texture.width / (float)texture.height); 38 | } 39 | 40 | var scaleOffset = gui.Canvas.GetTexScaleOffset(); 41 | 42 | gui.Canvas.PushTexture(texture); 43 | gui.Canvas.SetTexScaleOffset(new Vector4(1, 1, 0, 0)); 44 | gui.Canvas.Rect(rect, White); 45 | gui.Canvas.SetTexScaleOffset(scaleOffset); 46 | gui.Canvas.PopTexture(); 47 | } 48 | 49 | public static void Image(this ImGui gui, Sprite sprite, ImRect rect, bool preserveAspect = false) 50 | { 51 | if (gui.Canvas.Cull(rect) || !sprite.texture) 52 | { 53 | return; 54 | } 55 | 56 | if (preserveAspect) 57 | { 58 | rect = rect.WithAspect(sprite.rect.width / sprite.rect.height); 59 | } 60 | 61 | gui.Canvas.PushTexture(sprite.texture); 62 | 63 | if (sprite.packed && sprite.packingMode == SpritePackingMode.Tight) 64 | { 65 | DrawSpriteMesh(gui, sprite, rect); 66 | } 67 | else 68 | { 69 | var textureSize = new Vector2(sprite.texture.width, sprite.texture.height); 70 | var textureRect = sprite.textureRect; 71 | var textureRectOffset = sprite.textureRectOffset; 72 | var spriteRect = sprite.rect; 73 | var scaleOffset = new Vector4(textureRect.width / textureSize.x, textureRect.height / textureSize.y, textureRect.x / textureSize.x, textureRect.y / textureSize.y); 74 | var scale = new Vector2(1.0f / (spriteRect.width / rect.W), 1.0f / (spriteRect.height / rect.H)); 75 | var posOffset = scale * textureRectOffset; 76 | var sizeDelta = scale * (spriteRect.size - textureRect.size); 77 | 78 | rect.Position += posOffset; 79 | rect.Size -= sizeDelta; 80 | 81 | var prevScaleOffset = gui.Canvas.GetTexScaleOffset(); 82 | gui.Canvas.SetTexScaleOffset(scaleOffset); 83 | gui.Canvas.Rect(rect, White); 84 | gui.Canvas.SetTexScaleOffset(prevScaleOffset); 85 | } 86 | 87 | gui.Canvas.PopTexture(); 88 | } 89 | 90 | // TODO (artem-s): at some point, should be moved to ImMeshDrawer 91 | private static void DrawSpriteMesh(ImGui gui, Sprite sprite, ImRect rect) 92 | { 93 | var vertices = sprite.GetVertexAttribute(VertexAttribute.Position); 94 | var indices = sprite.GetIndices(); 95 | var uvs = sprite.GetVertexAttribute(VertexAttribute.TexCoord0); 96 | 97 | #if UNITY_EDITOR 98 | if (vertices.Length > 0) 99 | { 100 | try 101 | { 102 | _ = vertices[0]; 103 | } 104 | catch (ObjectDisposedException) 105 | { 106 | // (artem-s): no other way to check whether underlying array is disposed, and that happens sometimes 107 | // when drawing in editor mode and using atlases 108 | return; 109 | } 110 | } 111 | #endif 112 | 113 | var buffer = gui.MeshDrawer.buffer; 114 | var offset = rect.Position + (rect.Size * (sprite.pivot / sprite.rect.size)); 115 | var bounds = sprite.bounds.size; 116 | 117 | buffer.EnsureVerticesCapacity(buffer.VerticesCount + vertices.Length); 118 | buffer.EnsureIndicesCapacity(buffer.IndicesCount + indices.Length); 119 | 120 | for (int i = 0; i < vertices.Length; ++i) 121 | { 122 | var vertexPosition = vertices[i]; 123 | 124 | ref var v = ref buffer.Vertices[buffer.VerticesCount + i]; 125 | v.Position.x = offset.x + (vertexPosition.x / bounds.x) * rect.W; 126 | v.Position.y = offset.y + (vertexPosition.y / bounds.y) * rect.H; 127 | v.UV = uvs[i]; 128 | v.Color = White; 129 | v.Atlas = gui.MeshDrawer.Atlas; 130 | } 131 | 132 | for (int i = 0; i < indices.Length; ++i) 133 | { 134 | buffer.Indices[buffer.IndicesCount + i] = indices[i] + buffer.VerticesCount; 135 | } 136 | 137 | buffer.AddVertices(vertices.Length); 138 | buffer.AddIndices(indices.Length); 139 | } 140 | } 141 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImTabsPane.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using Imui.Core; 4 | 5 | namespace Imui.Controls 6 | { 7 | [Flags] 8 | public enum ImTabsPaneFlags 9 | { 10 | None = 0, 11 | NonScrollableContent = 1 << 0 12 | } 13 | 14 | public struct ImTabsPaneState 15 | { 16 | public ImRect Content; 17 | public uint Selected; 18 | public ImTabsPaneFlags Flags; 19 | } 20 | 21 | public static unsafe class ImTabsPane 22 | { 23 | public static ImRect AddButtonRect(ImGui gui, ReadOnlySpan label, ImSize size) 24 | { 25 | if (size.Mode == ImSizeMode.Fixed) 26 | { 27 | return gui.AddLayoutRect(size.Width, size.Height); 28 | } 29 | 30 | var width = gui.MeasureTextSize(label, GetTextSettings(gui)).x; 31 | 32 | return gui.AddLayoutRect(width + gui.Style.Layout.Indent * 2, GetTabBarHeight(gui)); 33 | } 34 | 35 | public static void BeginTabsPane(this ImGui gui, ImRect rect, ImTabsPaneFlags flags = ImTabsPaneFlags.None) 36 | { 37 | var id = gui.GetNextControlId(); 38 | var state = gui.BeginScopeUnsafe(id); 39 | var buttonsRect = rect.TakeTop(GetTabBarHeight(gui), out state->Content); 40 | 41 | state->Flags = flags; 42 | 43 | gui.Layout.Push(ImAxis.Horizontal, buttonsRect); 44 | gui.BeginScrollable(); 45 | } 46 | 47 | public static void EndTabsPane(this ImGui gui) 48 | { 49 | gui.EndScrollable(ImScrollFlag.HideVerBar | ImScrollFlag.HideHorBar); 50 | gui.Layout.Pop(); 51 | 52 | gui.EndScope(); 53 | } 54 | 55 | public static bool BeginTab(this ImGui gui, ReadOnlySpan label) 56 | { 57 | var id = gui.GetNextControlId(); 58 | var rect = AddButtonRect(gui, label, default); 59 | var state = gui.GetCurrentScopeUnsafe(); 60 | 61 | if (state->Selected == 0) 62 | { 63 | state->Selected = id; 64 | } 65 | 66 | if (TabBarButton(gui, id, state->Selected == id, label, rect)) 67 | { 68 | state->Selected = id; 69 | } 70 | 71 | if (state->Selected != id) 72 | { 73 | return false; 74 | } 75 | 76 | gui.Box(state->Content, in gui.Style.Tabs.ContainerBox); 77 | 78 | if (gui.Style.Tabs.SeparatorThickness > 0.0f) 79 | { 80 | var sepRect = state->Content.TakeTop(gui.Style.Tabs.SeparatorThickness); 81 | gui.Canvas.Rect(sepRect, gui.Style.Tabs.SeparatorColor); 82 | } 83 | else 84 | { 85 | CoverSeam(gui, state->Content, rect); 86 | } 87 | 88 | gui.PushId(id); 89 | gui.Layout.Push(ImAxis.Vertical, state->Content.WithPadding(gui.Style.Layout.Spacing)); 90 | 91 | if ((state->Flags & ImTabsPaneFlags.NonScrollableContent) == 0) 92 | { 93 | gui.PushId(id); 94 | gui.BeginScrollable(); 95 | gui.PopId(); 96 | } 97 | 98 | var maskRect = state->Content.WithPadding(gui.Style.Tabs.ContainerBox.BorderThickness); 99 | gui.Canvas.PushRectMask(maskRect, gui.Style.Tabs.ContainerBox.BorderRadius); 100 | gui.Canvas.PushClipRect(maskRect); 101 | 102 | return true; 103 | } 104 | 105 | public static void EndTab(this ImGui gui) 106 | { 107 | var state = gui.GetCurrentScopeUnsafe(); 108 | 109 | gui.Canvas.PopClipRect(); 110 | gui.Canvas.PopRectMask(); 111 | 112 | // TODO (artem-s): add flag dynamically resize tab's container to fit content 113 | // var rect = gui.Layout.GetWholeRect(); 114 | // var state = gui.PeekControlScopePtr(); 115 | // 116 | // state->Content = rect; 117 | 118 | if ((state->Flags & ImTabsPaneFlags.NonScrollableContent) == 0) 119 | { 120 | gui.EndScrollable(); 121 | } 122 | 123 | gui.Layout.Pop(); 124 | gui.PopId(); 125 | } 126 | 127 | public static bool TabBarButton(ImGui gui, uint id, bool selected, ReadOnlySpan label, ImRect rect) 128 | { 129 | ref readonly var buttonStyle = ref (selected ? ref gui.Style.Tabs.Selected : ref gui.Style.Tabs.Normal); 130 | 131 | var clicked = gui.Button(id, rect, in buttonStyle, out var state); 132 | var frontColor = ImButton.GetStateFrontColor(in buttonStyle, state); 133 | var textSettings = GetTextSettings(gui); 134 | 135 | gui.Text(label, in textSettings, frontColor, rect); 136 | 137 | return clicked; 138 | } 139 | 140 | private static void CoverSeam(ImGui gui, ImRect content, ImRect button) 141 | { 142 | var rect = button.TakeBottom(gui.Style.Button.BorderThickness + gui.Style.Tabs.ContainerBox.BorderThickness); 143 | 144 | rect.Y -= gui.Style.Tabs.ContainerBox.BorderThickness * 2.0f; 145 | rect.H += gui.Style.Tabs.ContainerBox.BorderThickness * 2.0f; 146 | rect.X += gui.Style.Button.BorderThickness; 147 | rect.W -= gui.Style.Button.BorderThickness * 2; 148 | 149 | gui.Canvas.Rect(rect, gui.Style.Tabs.ContainerBox.BackColor); 150 | } 151 | 152 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 153 | public static ImTextSettings GetTextSettings(ImGui gui) => new(gui.Style.Layout.TextSize, 0.5f, 0.5f); 154 | 155 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 156 | public static float GetTabBarHeight(ImGui gui) => gui.GetRowHeight(); 157 | } 158 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Style/ImColorHcl.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace Imui.Style 4 | { 5 | public struct ImColorHcl 6 | { 7 | public float Hue; 8 | public float Chroma; 9 | public float Lightness; 10 | public float Alpha; 11 | 12 | public ImColorHcl(Vector3 hcl, float alpha) 13 | { 14 | Hue = hcl.x; 15 | Chroma = hcl.y; 16 | Lightness = hcl.z; 17 | Alpha = alpha; 18 | } 19 | 20 | public ImColorHcl(float h, float c, float l, float alpha) 21 | { 22 | Hue = h; 23 | Chroma = c; 24 | Lightness = l; 25 | Alpha = alpha; 26 | } 27 | 28 | public ImColorHcl AddLightness(float lightness) 29 | { 30 | return new ImColorHcl(Hue, Chroma, Mathf.Clamp(Lightness + lightness, 0, 100), Alpha); 31 | } 32 | 33 | public ImColorHcl SetLightness(float lightness) 34 | { 35 | return new ImColorHcl(Hue, Chroma, Mathf.Clamp(lightness, 0, 100), Alpha); 36 | } 37 | 38 | public ImColorHcl AddAlpha(float value) 39 | { 40 | return new ImColorHcl(Hue, Chroma, Lightness, Mathf.Clamp01(Alpha + value)); 41 | } 42 | 43 | public ImColorHcl MulAlpha(float value) 44 | { 45 | return new ImColorHcl(Hue, Chroma, Lightness, Mathf.Clamp01(Alpha * value)); 46 | } 47 | 48 | public ImColorHcl SetAlpha(float value) 49 | { 50 | return new ImColorHcl(Hue, Chroma, Lightness, Mathf.Clamp01(value)); 51 | } 52 | 53 | public static implicit operator Color(ImColorHcl col) 54 | { 55 | return col.ToRgb(); 56 | } 57 | } 58 | 59 | public static class ImColorHclUtility 60 | { 61 | public static ImColorHcl ToHcl(this Color color) => new(RgbToHcl(color), color.a); 62 | 63 | public static Color ToRgb(this ImColorHcl hcl) 64 | { 65 | var rgba = HclToRgb(hcl.Hue, hcl.Chroma, hcl.Lightness); 66 | rgba.a = hcl.Alpha; 67 | return rgba; 68 | } 69 | 70 | private const float XN = 95.047f; 71 | private const float YN = 100.000f; 72 | private const float ZN = 108.883f; 73 | 74 | private static float PivotXyz(float n) 75 | { 76 | return (n > 0.008856f) ? Mathf.Pow(n, 1f / 3f) : (7.787f * n + 16f / 116f); 77 | } 78 | 79 | private static float InversePivotXyz(float n) 80 | { 81 | var n3 = Mathf.Pow(n, 3); 82 | return (n3 > 0.008856f) ? n3 : (n - 16f / 116f) / 7.787f; 83 | } 84 | 85 | private static Vector3 RgbToXyz(Color c) 86 | { 87 | var R = SrgbToLinear(c.r) * 100f; 88 | var G = SrgbToLinear(c.g) * 100f; 89 | var B = SrgbToLinear(c.b) * 100f; 90 | 91 | return new Vector3(R * 0.4124f + G * 0.3576f + B * 0.1805f, 92 | R * 0.2126f + G * 0.7152f + B * 0.0722f, 93 | R * 0.0193f + G * 0.1192f + B * 0.9505f); 94 | } 95 | 96 | private static Color XyzToRgb(Vector3 xyz) 97 | { 98 | var x = xyz.x / 100f; 99 | var y = xyz.y / 100f; 100 | var z = xyz.z / 100f; 101 | 102 | var R = x * 3.2406f + y * -1.5372f + z * -0.4986f; 103 | var G = x * -0.9689f + y * 1.8758f + z * 0.0415f; 104 | var B = x * 0.0557f + y * -0.2040f + z * 1.0570f; 105 | 106 | return new Color(Mathf.Clamp01(LinearToSrgb(R)), 107 | Mathf.Clamp01(LinearToSrgb(G)), 108 | Mathf.Clamp01(LinearToSrgb(B)), 109 | 1f); 110 | } 111 | 112 | private static Vector3 XyzToLab(Vector3 xyz) 113 | { 114 | var fx = PivotXyz(xyz.x / XN); 115 | var fy = PivotXyz(xyz.y / YN); 116 | var fz = PivotXyz(xyz.z / ZN); 117 | 118 | var L = 116f * fy - 16f; 119 | var a = 500f * (fx - fy); 120 | var b = 200f * (fy - fz); 121 | 122 | return new Vector3(L, a, b); 123 | } 124 | 125 | private static Vector3 LabToXyz(Vector3 lab) 126 | { 127 | var fy = (lab.x + 16f) / 116f; 128 | var fx = fy + (lab.y / 500f); 129 | var fz = fy - (lab.z / 200f); 130 | 131 | var xr = InversePivotXyz(fx); 132 | var yr = InversePivotXyz(fy); 133 | var zr = InversePivotXyz(fz); 134 | 135 | return new Vector3(xr * XN, yr * YN, zr * ZN); 136 | } 137 | 138 | public static Vector3 RgbToHcl(Color color) 139 | { 140 | var lab = XyzToLab(RgbToXyz(color)); 141 | 142 | var h = Mathf.Atan2(lab.z, lab.y); // atan2(b, a) 143 | if (h < 0) 144 | { 145 | h += 2f * Mathf.PI; 146 | } 147 | 148 | var hue = h * Mathf.Rad2Deg; 149 | 150 | var chroma = Mathf.Sqrt(lab.y * lab.y + lab.z * lab.z); 151 | var luminance = lab.x; 152 | 153 | return new Vector3(hue, chroma, luminance); // HCL 154 | } 155 | 156 | public static Color HclToRgb(float hue, float chroma, float luminance) 157 | { 158 | var hRad = hue * Mathf.Deg2Rad; 159 | 160 | var a = Mathf.Cos(hRad) * chroma; 161 | var b = Mathf.Sin(hRad) * chroma; 162 | 163 | var lab = new Vector3(luminance, a, b); 164 | var xyz = LabToXyz(lab); 165 | 166 | return XyzToRgb(xyz); 167 | } 168 | 169 | private static float SrgbToLinear(float c) 170 | { 171 | return (c <= 0.04045f) ? c / 12.92f : Mathf.Pow((c + 0.055f) / 1.055f, 2.4f); 172 | } 173 | 174 | private static float LinearToSrgb(float c) 175 | { 176 | return (c <= 0.0031308f) ? 12.92f * c : 1.055f * Mathf.Pow(c, 1.0f / 2.4f) - 0.055f; 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImVector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Style; 4 | using UnityEngine; 5 | 6 | namespace Imui.Controls 7 | { 8 | public static unsafe class ImVector 9 | { 10 | private static ImRect AddSpacingAndGetRect(ImGui gui, ImSize size) 11 | { 12 | gui.AddSpacingIfLayoutFrameNotEmpty(); 13 | return gui.AddSingleRowRect(size); 14 | } 15 | 16 | public static bool Vector(this ImGui gui, ref Vector2 value, ImSize size = default) => Vector(gui, ref value, AddSpacingAndGetRect(gui, size)); 17 | public static bool Vector(this ImGui gui, ref Vector3 value, ImSize size = default) => Vector(gui, ref value, AddSpacingAndGetRect(gui, size)); 18 | public static bool Vector(this ImGui gui, ref Vector4 value, ImSize size = default) => Vector(gui, ref value, AddSpacingAndGetRect(gui, size)); 19 | public static bool Vector(this ImGui gui, ref Vector2Int value, ImSize size = default) => Vector(gui, ref value, AddSpacingAndGetRect(gui, size)); 20 | public static bool Vector(this ImGui gui, ref Vector3Int value, ImSize size = default) => Vector(gui, ref value, AddSpacingAndGetRect(gui, size)); 21 | 22 | public static bool Vector(this ImGui gui, ref Vector2 value, ImRect rect) 23 | { 24 | var columns = gui.Arena.AllocArray(2); 25 | rect.SplitHorizontal(ref columns, columns.Length, gui.Style.Layout.Spacing); 26 | 27 | var changed = false; 28 | 29 | changed |= Component(gui, gui.GetNextControlId(), ref value.x, columns[0], 'x'); 30 | changed |= Component(gui, gui.GetNextControlId(), ref value.y, columns[1], 'y'); 31 | 32 | return changed; 33 | } 34 | 35 | public static bool Vector(this ImGui gui, ref Vector3 value, ImRect rect) 36 | { 37 | var columns = gui.Arena.AllocArray(3); 38 | rect.SplitHorizontal(ref columns, columns.Length, gui.Style.Layout.Spacing); 39 | 40 | var changed = false; 41 | 42 | changed |= Component(gui, gui.GetNextControlId(), ref value.x, columns[0], 'x'); 43 | changed |= Component(gui, gui.GetNextControlId(), ref value.y, columns[1], 'y'); 44 | changed |= Component(gui, gui.GetNextControlId(), ref value.z, columns[2], 'z'); 45 | 46 | return changed; 47 | } 48 | 49 | public static bool Vector(this ImGui gui, ref Vector4 value, ImRect rect) 50 | { 51 | var columns = gui.Arena.AllocArray(4); 52 | rect.SplitHorizontal(ref columns, columns.Length, gui.Style.Layout.Spacing); 53 | 54 | var changed = false; 55 | 56 | changed |= Component(gui, gui.GetNextControlId(), ref value.x, columns[0], 'x'); 57 | changed |= Component(gui, gui.GetNextControlId(), ref value.y, columns[1], 'y'); 58 | changed |= Component(gui, gui.GetNextControlId(), ref value.z, columns[2], 'z'); 59 | changed |= Component(gui, gui.GetNextControlId(), ref value.w, columns[3], 'w'); 60 | 61 | return changed; 62 | } 63 | 64 | public static bool Vector(this ImGui gui, ref Vector2Int value, ImRect rect) 65 | { 66 | var columns = gui.Arena.AllocArray(2); 67 | rect.SplitHorizontal(ref columns, columns.Length, gui.Style.Layout.Spacing); 68 | 69 | var changed = false; 70 | var x = value.x; 71 | var y = value.y; 72 | 73 | if (Component(gui, gui.GetNextControlId(), ref x, columns[0], 'x')) 74 | { 75 | value.x = x; 76 | changed = true; 77 | } 78 | 79 | if (Component(gui, gui.GetNextControlId(), ref y, columns[1], 'y')) 80 | { 81 | value.y = y; 82 | changed = true; 83 | } 84 | 85 | return changed; 86 | } 87 | 88 | public static bool Vector(this ImGui gui, ref Vector3Int value, ImRect rect) 89 | { 90 | var columns = gui.Arena.AllocArray(3); 91 | rect.SplitHorizontal(ref columns, columns.Length, gui.Style.Layout.Spacing); 92 | 93 | var changed = false; 94 | var x = value.x; 95 | var y = value.y; 96 | var z = value.z; 97 | 98 | if (Component(gui, gui.GetNextControlId(), ref x, columns[0], 'x')) 99 | { 100 | value.x = x; 101 | changed = true; 102 | } 103 | 104 | if (Component(gui, gui.GetNextControlId(), ref y, columns[1], 'y')) 105 | { 106 | value.y = y; 107 | changed = true; 108 | } 109 | 110 | if (Component(gui, gui.GetNextControlId(), ref z, columns[2], 'z')) 111 | { 112 | value.z = z; 113 | changed = true; 114 | } 115 | 116 | return changed; 117 | } 118 | 119 | public static bool Component(ImGui gui, uint id, ref float value, ImRect rect, char component) 120 | { 121 | var group = new ImGroup(gui, rect, 2); 122 | group.SetNextSize(gui.GetRowHeight() * 0.75f); 123 | ComponentLiteral(gui, group.GetNext(), component); 124 | return group.NumericEdit(id, ref value); 125 | } 126 | 127 | public static bool Component(ImGui gui, uint id, ref int value, ImRect rect, char component) 128 | { 129 | var group = new ImGroup(gui, rect, 2); 130 | group.SetNextSize(gui.GetRowHeight() * 0.75f); 131 | ComponentLiteral(gui, group.GetNext(), component); 132 | return group.NumericEdit(id, ref value); 133 | } 134 | 135 | public static void ComponentLiteral(ImGui gui, ImGroup.Item item, char component) 136 | { 137 | var textStyle = new ImTextSettings(gui.Style.Layout.TextSize * 0.75f, 0.5f, 0.5f); 138 | var componentText = new ReadOnlySpan(&component, 1); 139 | var componentStyle = gui.Style.TextEdit.Normal.Box; 140 | 141 | componentStyle.BorderRadius.Apply(item.Flags); 142 | 143 | gui.Box(item.Rect, in componentStyle); 144 | gui.Text(componentText, textStyle, item.Rect); 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Core/ImFormatter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Utility; 3 | 4 | namespace Imui.Core 5 | { 6 | public class ImFormatter 7 | { 8 | private ImArena arena; 9 | 10 | public ImFormatter(ImArena arena) 11 | { 12 | this.arena = arena; 13 | } 14 | 15 | public Span Concat(ReadOnlySpan str, int value) 16 | { 17 | var valueSpan = Format(value); 18 | var span = arena.AllocArray(str.Length + valueSpan.Length); 19 | var size = 0; 20 | str.CopyTo(span[size..]); 21 | size += str.Length; 22 | valueSpan.CopyTo(span[size..]); 23 | return span; 24 | } 25 | 26 | public Span Concat(ReadOnlySpan str, float value) 27 | { 28 | var valueSpan = Format(value); 29 | var span = arena.AllocArray(str.Length + valueSpan.Length); 30 | var size = 0; 31 | str.CopyTo(span[size..]); 32 | size += str.Length; 33 | str.CopyTo(span[size..]); 34 | return span; 35 | } 36 | 37 | public Span Concat(ReadOnlySpan str0, ReadOnlySpan str1) 38 | { 39 | var span = arena.AllocArray(str0.Length + str1.Length); 40 | var size = 0; 41 | str0.CopyTo(span[size..]); 42 | size += str0.Length; 43 | str1.CopyTo(span[size..]); 44 | return span; 45 | } 46 | 47 | public Span Concat(ReadOnlySpan str0, ReadOnlySpan str1, ReadOnlySpan str2) 48 | { 49 | var span = arena.AllocArray(str0.Length + str1.Length + str2.Length); 50 | var size = 0; 51 | str0.CopyTo(span[size..]); 52 | size += str0.Length; 53 | str1.CopyTo(span[size..]); 54 | size += str1.Length; 55 | str2.CopyTo(span[size..]); 56 | return span; 57 | } 58 | 59 | public Span Concat(ReadOnlySpan str0, ReadOnlySpan str1, ReadOnlySpan str2, ReadOnlySpan str3) 60 | { 61 | var span = arena.AllocArray(str0.Length + str1.Length + str2.Length + str3.Length); 62 | var size = 0; 63 | str0.CopyTo(span[size..]); 64 | size += str0.Length; 65 | str1.CopyTo(span[size..]); 66 | size += str1.Length; 67 | str2.CopyTo(span[size..]); 68 | size += str2.Length; 69 | str3.CopyTo(span[size..]); 70 | return span; 71 | } 72 | 73 | public Span Concat(ReadOnlySpan str0, ReadOnlySpan str1, ReadOnlySpan str2, ReadOnlySpan str3, ReadOnlySpan str4) 74 | { 75 | var span = arena.AllocArray(str0.Length + str1.Length + str2.Length + str3.Length + str4.Length); 76 | var size = 0; 77 | str0.CopyTo(span[size..]); 78 | size += str0.Length; 79 | str1.CopyTo(span[size..]); 80 | size += str1.Length; 81 | str2.CopyTo(span[size..]); 82 | size += str2.Length; 83 | str3.CopyTo(span[size..]); 84 | size += str3.Length; 85 | str4.CopyTo(span[size..]); 86 | return span; 87 | } 88 | 89 | 90 | public Span ConcatDuplicate(ReadOnlySpan str0, ReadOnlySpan str1, int repeat) 91 | { 92 | var span = arena.AllocArray(str0.Length + str1.Length * (repeat < 0 ? 0 : repeat)); 93 | var size = 0; 94 | str0.CopyTo(span[size..]); 95 | size += str0.Length; 96 | for (int i = 0; i < repeat; ++i) 97 | { 98 | str1.CopyTo(span[size..]); 99 | size += str1.Length; 100 | } 101 | 102 | return span; 103 | } 104 | 105 | public ReadOnlySpan Format(long value, ReadOnlySpan format = default) 106 | { 107 | var span = arena.AllocArray(512); 108 | if (value.TryFormat(span, out var written, format)) 109 | { 110 | return arena.ReallocArray(ref span, written); 111 | } 112 | 113 | return ReadOnlySpan.Empty; 114 | } 115 | 116 | public ReadOnlySpan Format(ulong value, ReadOnlySpan format = default) 117 | { 118 | var span = arena.AllocArray(512); 119 | if (value.TryFormat(span, out var written, format)) 120 | { 121 | return arena.ReallocArray(ref span, written); 122 | } 123 | 124 | return ReadOnlySpan.Empty; 125 | } 126 | 127 | public ReadOnlySpan Format(double value, ReadOnlySpan format = default) 128 | { 129 | var span = arena.AllocArray(512); 130 | if (value.TryFormat(span, out var written, format)) 131 | { 132 | return arena.ReallocArray(ref span, written); 133 | } 134 | 135 | return ReadOnlySpan.Empty; 136 | } 137 | 138 | public Span FormatEnum(TEnum value) where TEnum: struct, Enum 139 | { 140 | const string SEPARATOR = ImEnumUtility.FLAGS_SEPARATOR; 141 | 142 | var names = ImEnumUtility.Names; 143 | var maxLength = 0; 144 | 145 | if (ImEnumUtility.IsFlags) 146 | { 147 | for (int i = 0; i < names.Length; ++i) 148 | { 149 | maxLength += names[i].Length; 150 | } 151 | 152 | maxLength += SEPARATOR.Length * (names.Length - 1); 153 | } 154 | else 155 | { 156 | for (int i = 0; i < names.Length; ++i) 157 | { 158 | maxLength = names[i].Length > maxLength ? names[i].Length : maxLength; 159 | } 160 | } 161 | 162 | if (maxLength <= 0) 163 | { 164 | return Span.Empty; 165 | } 166 | 167 | var span = arena.AllocArray(maxLength); 168 | var written = ImEnumUtility.Format(value, span, SEPARATOR); 169 | 170 | return arena.ReallocArray(ref span, written); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /Runtime/Scripts/IO/Touch/ImTouchKeyboard.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.IO.Events; 3 | using UnityEngine; 4 | 5 | #if ENABLE_INPUT_SYSTEM 6 | using UnityEngine.InputSystem; 7 | using UnityEngine.InputSystem.LowLevel; 8 | #endif 9 | 10 | namespace Imui.IO.Touch 11 | { 12 | public enum ImTouchKeyboardType 13 | { 14 | Default, 15 | Numeric 16 | } 17 | 18 | public struct ImTouchKeyboardSettings 19 | { 20 | public bool Muiltiline; 21 | public ImTouchKeyboardType Type; 22 | public int CharactersLimit; 23 | public RangeInt Selection; 24 | } 25 | 26 | public class ImTouchKeyboard: IDisposable 27 | { 28 | private const int TOUCH_KEYBOARD_CLOSE_FRAMES_THRESHOLD = 3; 29 | 30 | public TouchScreenKeyboard TouchKeyboard; 31 | 32 | public bool NativeInputFieldHidden 33 | { 34 | get 35 | { 36 | var inputFieldHidden = TouchScreenKeyboard.hideInput; 37 | 38 | #if UNITY_6000_0_OR_NEWER 39 | inputFieldHidden |= TouchScreenKeyboard.inputFieldAppearance == TouchScreenKeyboard.InputFieldAppearance.AlwaysHidden; 40 | #endif 41 | 42 | return inputFieldHidden; 43 | } 44 | } 45 | 46 | private uint touchKeyboardOwner; 47 | private int touchKeyboardRequestFrame; 48 | private bool textInputDirty; 49 | 50 | public ImTouchKeyboard() 51 | { 52 | #if ENABLE_INPUT_SYSTEM 53 | if (Keyboard.current != null) 54 | { 55 | Keyboard.current.onIMECompositionChange += OnTextInput; 56 | } 57 | #endif 58 | } 59 | 60 | #if ENABLE_INPUT_SYSTEM 61 | private void OnTextInput(IMECompositionString c) 62 | { 63 | textInputDirty = true; 64 | } 65 | #endif 66 | 67 | public void RequestTouchKeyboard(uint owner, ReadOnlySpan text, ImTouchKeyboardSettings settings) 68 | { 69 | #if UNITY_WEBGL 70 | // TODO (artem-s): fix touch keyboard handling for webgl 71 | return; 72 | #endif 73 | 74 | if (!TouchScreenKeyboard.isSupported) 75 | { 76 | return; 77 | } 78 | 79 | if (owner != touchKeyboardOwner && TouchKeyboard != null) 80 | { 81 | TouchKeyboard.active = false; 82 | TouchKeyboard = null; 83 | touchKeyboardOwner = 0; 84 | } 85 | 86 | if (TouchKeyboard == null) 87 | { 88 | touchKeyboardOwner = owner; 89 | TouchKeyboard = TouchScreenKeyboard.Open( 90 | new string(text), 91 | GetType(settings.Type), 92 | false, 93 | settings.Muiltiline); 94 | 95 | TouchKeyboard.characterLimit = settings.CharactersLimit; 96 | TouchKeyboard.selection = settings.Selection; 97 | } 98 | 99 | if (!TouchKeyboard.active) 100 | { 101 | TouchKeyboard.active = true; 102 | } 103 | 104 | if (NativeInputFieldHidden && TouchKeyboard.active && TouchKeyboard.canSetSelection) 105 | { 106 | var prev = TouchKeyboard.selection; 107 | var changed = prev.start != settings.Selection.start || prev.length != settings.Selection.length; 108 | if (changed) 109 | { 110 | // (artem-s): setting selection does allocate currently edited string for range checking 111 | TouchKeyboard.selection = settings.Selection; 112 | } 113 | } 114 | 115 | touchKeyboardRequestFrame = Time.frameCount; 116 | } 117 | 118 | private TouchScreenKeyboardType GetType(ImTouchKeyboardType type) 119 | { 120 | switch (type) 121 | { 122 | case ImTouchKeyboardType.Numeric: 123 | return TouchScreenKeyboardType.NumbersAndPunctuation; 124 | default: 125 | return TouchScreenKeyboardType.Default; 126 | } 127 | } 128 | 129 | public void HandleTouchKeyboard(out ImTextEvent textEvent) 130 | { 131 | var textDirty = textInputDirty; 132 | 133 | textInputDirty = false; 134 | textEvent = default; 135 | 136 | if (TouchKeyboard != null) 137 | { 138 | var shouldHide = Mathf.Abs(Time.frameCount - touchKeyboardRequestFrame) > TOUCH_KEYBOARD_CLOSE_FRAMES_THRESHOLD; 139 | 140 | switch (TouchKeyboard.status) 141 | { 142 | case TouchScreenKeyboard.Status.Visible when NativeInputFieldHidden: 143 | var sendEvent = textDirty; 144 | #if !ENABLE_INPUT_SYSTEM 145 | sendEvent |= Input.inputString?.Length > 0; 146 | #endif 147 | 148 | if (sendEvent) 149 | { 150 | var text = TouchKeyboard.text; 151 | // TODO (artem-s): would be nice to update selection even when text itself hasn't changed 152 | RangeInt? selection = TouchKeyboard.canGetSelection ? TouchKeyboard.selection : null; 153 | textEvent = new ImTextEvent(ImTextEventType.Set, text, selection); 154 | } 155 | break; 156 | case TouchScreenKeyboard.Status.Canceled: 157 | textEvent = new ImTextEvent(ImTextEventType.Cancel); 158 | shouldHide = true; 159 | break; 160 | case TouchScreenKeyboard.Status.Done: 161 | textEvent = new ImTextEvent(ImTextEventType.Submit, TouchKeyboard.text); 162 | shouldHide = true; 163 | break; 164 | } 165 | 166 | if (shouldHide) 167 | { 168 | TouchKeyboard.active = false; 169 | TouchKeyboard = null; 170 | } 171 | } 172 | } 173 | 174 | public void Dispose() 175 | { 176 | #if ENABLE_INPUT_SYSTEM 177 | if (Keyboard.current != null) 178 | { 179 | Keyboard.current.onIMECompositionChange -= OnTextInput; 180 | } 181 | #endif 182 | 183 | if (TouchKeyboard != null) 184 | { 185 | TouchKeyboard.active = false; 186 | TouchKeyboard = null; 187 | } 188 | } 189 | } 190 | } -------------------------------------------------------------------------------- /Runtime/Scripts/Controls/ImText.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Imui.Core; 3 | using Imui.Rendering; 4 | using Imui.Style; 5 | using UnityEngine; 6 | 7 | namespace Imui.Controls 8 | { 9 | public static class ImText 10 | { 11 | public const float MIN_WIDTH = 1; 12 | public const float MIN_HEIGHT = 1; 13 | 14 | public static void Text(this ImGui gui, ReadOnlySpan text, bool wrap = false, ImTextOverflow overflow = ImTextOverflow.Overflow) 15 | { 16 | Text(gui, text, GetTextSettings(gui, wrap, overflow)); 17 | } 18 | 19 | public static void Text(this ImGui gui, ReadOnlySpan text, Color32 color, bool wrap = false, ImTextOverflow overflow = ImTextOverflow.Overflow) 20 | { 21 | Text(gui, text, GetTextSettings(gui, wrap, overflow), color); 22 | } 23 | 24 | public static void Text(this ImGui gui, ReadOnlySpan text, ImRect rect, bool wrap = false, ImTextOverflow overflow = ImTextOverflow.Overflow) 25 | { 26 | Text(gui, text, GetTextSettings(gui, wrap, overflow), rect); 27 | } 28 | 29 | public static void Text(this ImGui gui, 30 | ReadOnlySpan text, 31 | Color32 color, 32 | ImRect rect, 33 | bool wrap = false, 34 | ImTextOverflow overflow = ImTextOverflow.Overflow) 35 | { 36 | Text(gui, text, GetTextSettings(gui, wrap, overflow), color, rect); 37 | } 38 | 39 | public static void TextAutoSize(this ImGui gui, ReadOnlySpan text, ImRect rect, bool wrap = false) 40 | { 41 | TextAutoSize(gui, text, gui.Style.Text.Color, rect, wrap); 42 | } 43 | 44 | public static void TextAutoSize(this ImGui gui, 45 | ReadOnlySpan text, 46 | Color32 color, 47 | ImRect rect, 48 | bool wrap = false, 49 | ImTextOverflow overflow = ImTextOverflow.Overflow, 50 | ImAlignment alignment = default) 51 | { 52 | // (artem-s): at least try to skip costly auto-sizing 53 | if (gui.Canvas.Cull(rect)) 54 | { 55 | return; 56 | } 57 | 58 | var settings = GetTextSettings(gui, wrap, overflow); 59 | settings.Align = alignment; 60 | settings.Size = AutoSizeTextSlow(gui, text, settings, rect.Size); 61 | Text(gui, text, settings, color, rect); 62 | } 63 | 64 | public static void Text(this ImGui gui, ReadOnlySpan text, in ImTextSettings settings) 65 | { 66 | Text(gui, text, in settings, gui.Style.Text.Color); 67 | } 68 | 69 | public static void Text(this ImGui gui, ReadOnlySpan text, in ImTextSettings settings, Color32 color) 70 | { 71 | gui.AddSpacingIfLayoutFrameNotEmpty(); 72 | 73 | var space = gui.Layout.GetAvailableSize().Max(MIN_WIDTH, MIN_HEIGHT); 74 | var rect = gui.Layout.GetRect(space); 75 | gui.Canvas.Text(text, color, rect, in settings, out var textRect); 76 | gui.Layout.AddRect(textRect); 77 | } 78 | 79 | public static void Text(this ImGui gui, ReadOnlySpan text, in ImTextSettings settings, ImRect rect) 80 | { 81 | gui.Canvas.Text(text, gui.Style.Text.Color, rect, in settings); 82 | } 83 | 84 | public static void Text(this ImGui gui, ReadOnlySpan text, in ImTextSettings settings, Color32 color, ImRect rect) 85 | { 86 | gui.Canvas.Text(text, color, rect, in settings); 87 | } 88 | 89 | public static ImTextSettings GetTextSettings(ImGui gui, bool wrap, ImTextOverflow overflow) 90 | { 91 | return new ImTextSettings(gui.Style.Layout.TextSize, 0.0f, 0.0f, wrap, overflow); 92 | } 93 | 94 | // TODO (artem-s): Got to come up with better solution instead of just brute forcing the fuck of it every time 95 | public static float AutoSizeTextSlow(this ImGui gui, ReadOnlySpan text, ImTextSettings settings, Vector2 bounds, float minSize = 1) 96 | { 97 | var textSize = gui.MeasureTextSize(text, in settings, bounds); 98 | while (settings.Size > minSize && (textSize.x > bounds.x || textSize.y > bounds.y)) 99 | { 100 | settings.Size -= 1; 101 | textSize = gui.MeasureTextSize(text, in settings, bounds); 102 | } 103 | 104 | return settings.Size; 105 | } 106 | 107 | public static float GetFontSizeForContainerHeight(this ImGui gui, float containerHeight) 108 | { 109 | var scale = containerHeight / gui.TextDrawer.FontLineHeight; 110 | return scale * gui.TextDrawer.FontRenderSize; 111 | } 112 | 113 | public static Vector2 MeasureTextSize(this ImGui gui, ReadOnlySpan text) 114 | { 115 | ref readonly var textLayout = ref gui.TextDrawer.BuildTempLayout(text, 116 | 0, 117 | 0, 118 | 0, 119 | 0, 120 | gui.Style.Layout.TextSize, 121 | false, 122 | ImTextOverflow.Overflow); 123 | 124 | return new Vector2(textLayout.Width, textLayout.Height); 125 | } 126 | 127 | public static Vector2 MeasureTextSize(this ImGui gui, ReadOnlySpan text, float textSize) 128 | { 129 | ref readonly var textLayout = ref gui.TextDrawer.BuildTempLayout(text, 130 | 0, 131 | 0, 132 | 0, 133 | 0, 134 | textSize, 135 | false, 136 | ImTextOverflow.Overflow); 137 | 138 | return new Vector2(textLayout.Width, textLayout.Height); 139 | } 140 | 141 | public static Vector2 MeasureTextSize(this ImGui gui, ReadOnlySpan text, in ImTextSettings textSettings, Vector2 bounds = default) 142 | { 143 | ref readonly var textLayout = ref gui.TextDrawer.BuildTempLayout(text, 144 | bounds.x, 145 | bounds.y, 146 | textSettings.Align.X, 147 | textSettings.Align.Y, 148 | textSettings.Size, 149 | textSettings.Wrap, 150 | textSettings.Overflow); 151 | 152 | return new Vector2(textLayout.Width, textLayout.Height); 153 | } 154 | } 155 | } --------------------------------------------------------------------------------