PyImGui 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyimgui-0.1.0/.github/workflows/wheels.yml +76 -0
- pyimgui-0.1.0/.gitignore +1 -0
- pyimgui-0.1.0/CMakeLists.txt +177 -0
- pyimgui-0.1.0/LICENSE +21 -0
- pyimgui-0.1.0/PKG-INFO +311 -0
- pyimgui-0.1.0/README.md +291 -0
- pyimgui-0.1.0/THIRD_PARTY_LICENSES.txt +242 -0
- pyimgui-0.1.0/generate.py +834 -0
- pyimgui-0.1.0/pyproject.toml +64 -0
- pyimgui-0.1.0/src/bindings/imgui_bindings.cpp +6819 -0
- pyimgui-0.1.0/src/bindings/imgui_config.h +25 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_dx12_bindings.cpp +163 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_metal_bindings.mm +164 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_opengl3_bindings.cpp +68 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_sdl3_bindings.cpp +95 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_sdlgpu3_bindings.cpp +91 -0
- pyimgui-0.1.0/src/bindings/imgui_impl_vulkan_bindings.cpp +367 -0
- pyimgui-0.1.0/src/bindings/imguizmo_bindings.cpp +388 -0
- pyimgui-0.1.0/src/bindings/implot_bindings.cpp +3864 -0
- pyimgui-0.1.0/src/bindings/module.cpp +57 -0
- pyimgui-0.1.0/src/bindings/native_casters.h +98 -0
- pyimgui-0.1.0/src/bindings/opaque_handle.h +65 -0
- pyimgui-0.1.0/src/bindings/sdl3_casters.h +109 -0
- pyimgui-0.1.0/src/bindings/style_colors.h +41 -0
- pyimgui-0.1.0/src/imgui/__init__.py +41 -0
- pyimgui-0.1.0/src/imgui/__init__.pyi +10140 -0
- pyimgui-0.1.0/src/imgui/app.py +219 -0
- pyimgui-0.1.0/src/imgui/app_dx12.py +673 -0
- pyimgui-0.1.0/src/imgui/app_metal4.py +251 -0
- pyimgui-0.1.0/src/imgui/app_opengl3.py +194 -0
- pyimgui-0.1.0/src/imgui/app_vulkan.py +805 -0
- pyimgui-0.1.0/src/imgui/imguizmo.pyi +501 -0
- pyimgui-0.1.0/src/imgui/impl_dx12.pyi +65 -0
- pyimgui-0.1.0/src/imgui/impl_metal.pyi +24 -0
- pyimgui-0.1.0/src/imgui/impl_metal4.pyi +34 -0
- pyimgui-0.1.0/src/imgui/impl_opengl3.pyi +81 -0
- pyimgui-0.1.0/src/imgui/impl_sdl3.pyi +100 -0
- pyimgui-0.1.0/src/imgui/impl_sdlgpu3.pyi +106 -0
- pyimgui-0.1.0/src/imgui/impl_vulkan.pyi +146 -0
- pyimgui-0.1.0/src/imgui/implot.pyi +2508 -0
- pyimgui-0.1.0/src/imgui/py.typed +0 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Builds the wheels and the sdist, and uploads them to PyPI when a GitHub release is
|
|
2
|
+
# published. Its tag has to be the version in pyproject.toml, with or without a
|
|
3
|
+
# leading "v". Run it by hand (Actions > Wheels > Run workflow) to build and test
|
|
4
|
+
# the wheels without uploading them.
|
|
5
|
+
#
|
|
6
|
+
# The upload uses PyPI's trusted publishing, which the PyPI project has to be set
|
|
7
|
+
# up for: https://docs.pypi.org/trusted-publishers/ (workflow wheels.yml,
|
|
8
|
+
# environment pypi).
|
|
9
|
+
name: Wheels
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
release:
|
|
14
|
+
types: [published]
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
wheels:
|
|
21
|
+
name: Wheels on ${{ matrix.os }}
|
|
22
|
+
runs-on: ${{ matrix.os }}
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
# The runners' own architectures: x86-64 and ARM64 for Linux and Windows,
|
|
27
|
+
# ARM64 for macOS. The wheels need macOS 26 (see pyproject.toml), which no
|
|
28
|
+
# Intel runner has to test them on.
|
|
29
|
+
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-latest]
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v7
|
|
32
|
+
# The options are in pyproject.toml ([tool.cibuildwheel])
|
|
33
|
+
- uses: pypa/cibuildwheel@v4.2.1
|
|
34
|
+
env:
|
|
35
|
+
# The tests import pysdl3, which downloads SDL3 through GitHub's API
|
|
36
|
+
SDL_GITHUB_TOKEN: ${{ github.token }}
|
|
37
|
+
- uses: actions/upload-artifact@v7
|
|
38
|
+
with:
|
|
39
|
+
name: wheels-${{ matrix.os }}
|
|
40
|
+
path: wheelhouse/*.whl
|
|
41
|
+
|
|
42
|
+
sdist:
|
|
43
|
+
name: Source distribution
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v7
|
|
47
|
+
- name: Check that the release tag is the version
|
|
48
|
+
if: github.event_name == 'release'
|
|
49
|
+
run: |
|
|
50
|
+
version=$(python3 -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
|
51
|
+
if [ "${GITHUB_REF_NAME#v}" != "$version" ]; then
|
|
52
|
+
echo "::error::The release tag $GITHUB_REF_NAME is not the version in pyproject.toml, $version"
|
|
53
|
+
exit 1
|
|
54
|
+
fi
|
|
55
|
+
- run: pipx run build --sdist
|
|
56
|
+
- uses: actions/upload-artifact@v7
|
|
57
|
+
with:
|
|
58
|
+
name: sdist
|
|
59
|
+
path: dist/*.tar.gz
|
|
60
|
+
|
|
61
|
+
publish:
|
|
62
|
+
name: Upload to PyPI
|
|
63
|
+
if: github.event_name == 'release'
|
|
64
|
+
needs: [wheels, sdist]
|
|
65
|
+
runs-on: ubuntu-latest
|
|
66
|
+
environment:
|
|
67
|
+
name: pypi
|
|
68
|
+
url: https://pypi.org/p/PyImGui
|
|
69
|
+
permissions:
|
|
70
|
+
id-token: write
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/download-artifact@v8
|
|
73
|
+
with:
|
|
74
|
+
path: dist
|
|
75
|
+
merge-multiple: true
|
|
76
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
pyimgui-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
build/
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.24...4.4)
|
|
2
|
+
project(imgui_bindings LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
|
|
7
|
+
# The Dear ImGui release that the bindings in src/ were generated from. generate.py
|
|
8
|
+
# reads the tag from this line, so the two cannot drift apart: bump it, rerun
|
|
9
|
+
# generate.py, rebuild, and update its notices in THIRD_PARTY_LICENSES.txt.
|
|
10
|
+
set(IMGUI_GIT_TAG v1.93.0-docking)
|
|
11
|
+
# The same for ImPlot and ImGuizmo, as commits: their last releases predate their
|
|
12
|
+
# fixes for the ImDrawList changes of Dear ImGui 1.92.8
|
|
13
|
+
set(IMPLOT_GIT_TAG 851cdbdd60d1dfb64c23e987969694de0f547a6b)
|
|
14
|
+
set(IMGUIZMO_GIT_TAG 105e4fde45e4e74aae8973d98750820ef7aca7e2)
|
|
15
|
+
|
|
16
|
+
# The SDL3 release whose headers the backends are compiled against. SDL3 itself is
|
|
17
|
+
# not linked (see _imgui below), so the SDL3 loaded at runtime has to be this
|
|
18
|
+
# release or a newer one.
|
|
19
|
+
set(SDL3_VERSION 3.4.16)
|
|
20
|
+
|
|
21
|
+
# The Vulkan headers that the Vulkan backend is compiled against. Vulkan itself is
|
|
22
|
+
# not linked either: the backend looks its functions up at runtime (see below).
|
|
23
|
+
set(VULKAN_HEADERS_GIT_TAG vulkan-sdk-1.4.363.0)
|
|
24
|
+
|
|
25
|
+
include(FetchContent)
|
|
26
|
+
# The archives' files get the time of their extraction (DOWNLOAD_EXTRACT_TIMESTAMP
|
|
27
|
+
# FALSE), not their dates in the archive: those predate the objects of an earlier
|
|
28
|
+
# release in the kept build directory (see pyproject.toml), which would then pass
|
|
29
|
+
# for up to date after bumping a release below.
|
|
30
|
+
FetchContent_Declare(imgui
|
|
31
|
+
URL https://github.com/ocornut/imgui/archive/refs/tags/${IMGUI_GIT_TAG}.tar.gz
|
|
32
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE)
|
|
33
|
+
# Only the headers of SDL3 are used: SOURCE_SUBDIR names a directory without a
|
|
34
|
+
# CMakeLists.txt, so SDL3 is downloaded but not built
|
|
35
|
+
FetchContent_Declare(sdl3
|
|
36
|
+
URL https://github.com/libsdl-org/SDL/releases/download/release-${SDL3_VERSION}/SDL3-${SDL3_VERSION}.tar.gz
|
|
37
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
|
38
|
+
SOURCE_SUBDIR include)
|
|
39
|
+
FetchContent_Declare(implot
|
|
40
|
+
URL https://github.com/epezent/implot/archive/${IMPLOT_GIT_TAG}.tar.gz
|
|
41
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE)
|
|
42
|
+
# ImGuizmo's own CMakeLists.txt builds all of its widgets: only ImGuizmo.cpp is compiled below
|
|
43
|
+
FetchContent_Declare(imguizmo
|
|
44
|
+
URL https://github.com/CedricGuillemet/ImGuizmo/archive/${IMGUIZMO_GIT_TAG}.tar.gz
|
|
45
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
|
46
|
+
SOURCE_SUBDIR src)
|
|
47
|
+
# Only the headers, as for SDL3
|
|
48
|
+
FetchContent_Declare(vulkan_headers
|
|
49
|
+
URL https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/${VULKAN_HEADERS_GIT_TAG}.tar.gz
|
|
50
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
|
|
51
|
+
SOURCE_SUBDIR include)
|
|
52
|
+
FetchContent_MakeAvailable(imgui sdl3 implot imguizmo vulkan_headers)
|
|
53
|
+
|
|
54
|
+
find_package(Python 3.12 REQUIRED COMPONENTS Interpreter Development.Module Development.SABIModule)
|
|
55
|
+
find_package(nanobind CONFIG REQUIRED)
|
|
56
|
+
|
|
57
|
+
# Dear ImGui, its C++ string helpers, the backends, ImPlot and ImGuizmo, compiled
|
|
58
|
+
# with the regular optimization flags (nanobind_add_module optimizes for size)
|
|
59
|
+
add_library(imgui STATIC
|
|
60
|
+
${imgui_SOURCE_DIR}/imgui.cpp
|
|
61
|
+
${imgui_SOURCE_DIR}/imgui_demo.cpp
|
|
62
|
+
${imgui_SOURCE_DIR}/imgui_draw.cpp
|
|
63
|
+
${imgui_SOURCE_DIR}/imgui_tables.cpp
|
|
64
|
+
${imgui_SOURCE_DIR}/imgui_widgets.cpp
|
|
65
|
+
${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp
|
|
66
|
+
${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
|
|
67
|
+
${imgui_SOURCE_DIR}/backends/imgui_impl_sdlgpu3.cpp
|
|
68
|
+
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
|
|
69
|
+
${imgui_SOURCE_DIR}/backends/imgui_impl_vulkan.cpp
|
|
70
|
+
${implot_SOURCE_DIR}/implot.cpp
|
|
71
|
+
${implot_SOURCE_DIR}/implot_items.cpp
|
|
72
|
+
${implot_SOURCE_DIR}/implot_demo.cpp
|
|
73
|
+
${imguizmo_SOURCE_DIR}/src/ImGuizmo.cpp)
|
|
74
|
+
target_include_directories(imgui PUBLIC
|
|
75
|
+
${imgui_SOURCE_DIR}
|
|
76
|
+
${imgui_SOURCE_DIR}/backends
|
|
77
|
+
${imgui_SOURCE_DIR}/misc/cpp
|
|
78
|
+
${implot_SOURCE_DIR}
|
|
79
|
+
${imguizmo_SOURCE_DIR}/src)
|
|
80
|
+
target_compile_definitions(imgui PUBLIC IMGUI_USER_CONFIG="imgui_config.h")
|
|
81
|
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
|
82
|
+
# IM_ASSERT throws (see imgui_config.h), which the few destructors that assert
|
|
83
|
+
# cannot pass on: an assertion that fails in one of them terminates instead
|
|
84
|
+
target_compile_options(imgui PUBLIC -Wno-exceptions)
|
|
85
|
+
endif()
|
|
86
|
+
target_include_directories(imgui PUBLIC src/bindings ${sdl3_SOURCE_DIR}/include)
|
|
87
|
+
set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
88
|
+
# OpenGL is not linked either: imgui_impl_opengl3_loader.h opens the system's
|
|
89
|
+
# OpenGL library at runtime (dlopen, or LoadLibrary on Windows) and looks up its
|
|
90
|
+
# functions there, in the GL context that is current
|
|
91
|
+
target_link_libraries(imgui PUBLIC ${CMAKE_DL_LIBS})
|
|
92
|
+
# Nor is Vulkan: without prototypes, the Vulkan backend calls the functions that
|
|
93
|
+
# ImGui_ImplVulkan_LoadFunctions() looks up, which the bindings do through the
|
|
94
|
+
# vkGetInstanceProcAddr of the Vulkan library that SDL3 loaded. Defined for the
|
|
95
|
+
# bindings as well, which have to see the same declarations.
|
|
96
|
+
target_include_directories(imgui PUBLIC ${vulkan_headers_SOURCE_DIR}/include)
|
|
97
|
+
target_compile_definitions(imgui PUBLIC IMGUI_IMPL_VULKAN_NO_PROTOTYPES)
|
|
98
|
+
|
|
99
|
+
# STABLE_ABI: the module uses the stable ABI only, so that one wheel (abi3, see
|
|
100
|
+
# pyproject.toml) serves every Python release from 3.12 on
|
|
101
|
+
nanobind_add_module(_imgui STABLE_ABI
|
|
102
|
+
src/bindings/module.cpp
|
|
103
|
+
src/bindings/imgui_bindings.cpp
|
|
104
|
+
src/bindings/imgui_impl_sdl3_bindings.cpp
|
|
105
|
+
src/bindings/imgui_impl_sdlgpu3_bindings.cpp
|
|
106
|
+
src/bindings/imgui_impl_opengl3_bindings.cpp
|
|
107
|
+
src/bindings/imgui_impl_vulkan_bindings.cpp
|
|
108
|
+
src/bindings/implot_bindings.cpp
|
|
109
|
+
src/bindings/imguizmo_bindings.cpp)
|
|
110
|
+
target_link_libraries(_imgui PRIVATE imgui)
|
|
111
|
+
|
|
112
|
+
# All of imgui_bindings.cpp's bindings sit in one function of some 6700 lines, which
|
|
113
|
+
# MSVC's optimizer takes superlinearly long to compile: around nine minutes, against
|
|
114
|
+
# the twelve seconds of the five other translation units together. Lowering the
|
|
115
|
+
# inlining level (/Ob1) does not help, so that one file is compiled unoptimized,
|
|
116
|
+
# which brings it down to some twenty seconds. The cost is a little overhead in the
|
|
117
|
+
# lambdas that forward to Dear ImGui, whose own code is optimized as usual in the
|
|
118
|
+
# imgui library above. /Od comes last and thus wins over the /O2 /Ob2 /Os of the
|
|
119
|
+
# release flags, which warns (D9025) but is exactly the intent.
|
|
120
|
+
if(MSVC)
|
|
121
|
+
set_source_files_properties(src/bindings/imgui_bindings.cpp
|
|
122
|
+
PROPERTIES COMPILE_OPTIONS "/Od")
|
|
123
|
+
endif()
|
|
124
|
+
|
|
125
|
+
# SDL3 is not linked: the module leaves its SDL functions unresolved, and they are
|
|
126
|
+
# looked up when it is loaded, in the SDL3 that pysdl3 loaded before (see
|
|
127
|
+
# src/imgui/__init__.py). The backends thus share pysdl3's SDL3, whose windows and
|
|
128
|
+
# events they are handed. Linux allows unresolved symbols in shared libraries as
|
|
129
|
+
# is, macOS has to be told; a Windows DLL cannot have any, so it links SDL3.dll,
|
|
130
|
+
# through the import library of the SDL3 release above. At runtime, Windows
|
|
131
|
+
# resolves SDL3.dll to the one pysdl3 has already loaded. The wheel must not bundle
|
|
132
|
+
# an SDL3.dll of its own (see the cibuildwheel options in pyproject.toml).
|
|
133
|
+
if(APPLE)
|
|
134
|
+
target_link_options(_imgui PRIVATE -Wl,-undefined,dynamic_lookup)
|
|
135
|
+
elseif(WIN32)
|
|
136
|
+
FetchContent_Declare(sdl3_devel
|
|
137
|
+
URL https://github.com/libsdl-org/SDL/releases/download/release-${SDL3_VERSION}/SDL3-devel-${SDL3_VERSION}-VC.zip
|
|
138
|
+
DOWNLOAD_EXTRACT_TIMESTAMP FALSE)
|
|
139
|
+
FetchContent_MakeAvailable(sdl3_devel)
|
|
140
|
+
find_package(SDL3 CONFIG REQUIRED COMPONENTS SDL3-shared PATHS ${sdl3_devel_SOURCE_DIR} NO_DEFAULT_PATH)
|
|
141
|
+
target_link_libraries(_imgui PRIVATE SDL3::SDL3-shared)
|
|
142
|
+
endif()
|
|
143
|
+
|
|
144
|
+
# The Direct3D 12 backend, on Windows. It loads d3d12.dll itself, and links DXGI and
|
|
145
|
+
# the shader compiler (d3dcompiler_47.dll), which are part of Windows.
|
|
146
|
+
if(WIN32)
|
|
147
|
+
target_sources(imgui PRIVATE ${imgui_SOURCE_DIR}/backends/imgui_impl_dx12.cpp)
|
|
148
|
+
target_link_libraries(imgui PUBLIC dxgi d3dcompiler)
|
|
149
|
+
target_sources(_imgui PRIVATE src/bindings/imgui_impl_dx12_bindings.cpp)
|
|
150
|
+
endif()
|
|
151
|
+
|
|
152
|
+
# The Metal backends, on macOS: Objective-C++, with ARC as Dear ImGui's examples
|
|
153
|
+
# build them. Both define Objective-C classes of the same names, which would clash
|
|
154
|
+
# when linked together (and with any other class of those names in the process,
|
|
155
|
+
# as the Objective-C runtime is global): each gets its own names.
|
|
156
|
+
if(APPLE)
|
|
157
|
+
enable_language(OBJCXX)
|
|
158
|
+
set(IMGUI_METAL_RENAMES
|
|
159
|
+
MetalBuffer MetalTexture MetalContext FramebufferDescriptor ImGuiViewportDataMetal shaderCode)
|
|
160
|
+
foreach(backend Metal Metal4)
|
|
161
|
+
string(TOLOWER ${backend} name)
|
|
162
|
+
set(renames)
|
|
163
|
+
foreach(symbol ${IMGUI_METAL_RENAMES})
|
|
164
|
+
list(APPEND renames "${symbol}=ImGui_Impl${backend}_${symbol}")
|
|
165
|
+
endforeach()
|
|
166
|
+
set_source_files_properties(${imgui_SOURCE_DIR}/backends/imgui_impl_${name}.mm PROPERTIES
|
|
167
|
+
COMPILE_DEFINITIONS "${renames}"
|
|
168
|
+
COMPILE_OPTIONS "-fobjc-arc;-fobjc-weak")
|
|
169
|
+
target_sources(imgui PRIVATE ${imgui_SOURCE_DIR}/backends/imgui_impl_${name}.mm)
|
|
170
|
+
endforeach()
|
|
171
|
+
target_link_libraries(imgui PUBLIC "-framework Metal" "-framework QuartzCore" "-framework Cocoa")
|
|
172
|
+
target_sources(_imgui PRIVATE src/bindings/imgui_impl_metal_bindings.mm)
|
|
173
|
+
set_source_files_properties(src/bindings/imgui_impl_metal_bindings.mm PROPERTIES
|
|
174
|
+
COMPILE_OPTIONS "-fobjc-arc")
|
|
175
|
+
endif()
|
|
176
|
+
|
|
177
|
+
install(TARGETS _imgui LIBRARY DESTINATION imgui)
|
pyimgui-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lukas Lipp
|
|
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.
|
pyimgui-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: PyImGui
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Python bindings for Dear ImGui, its SDL3, SDL_GPU, OpenGL 3, Vulkan, Direct3D 12 and Metal backends, ImPlot and ImGuizmo
|
|
5
|
+
Keywords: imgui,implot,imguizmo,sdl3,sdl_gpu,opengl,vulkan,direct3d12,metal,gui,plot,gizmo,bindings
|
|
6
|
+
Author-Email: Lukas Lipp <lukas.lipp@cg.tuwien.ac.at>
|
|
7
|
+
License-Expression: MIT AND BSD-3-Clause
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
License-File: THIRD_PARTY_LICENSES.txt
|
|
10
|
+
Project-URL: Homepage, https://github.com/fknfilewalker/PyImGui
|
|
11
|
+
Project-URL: Source, https://github.com/fknfilewalker/PyImGui
|
|
12
|
+
Project-URL: Issues, https://github.com/fknfilewalker/PyImGui/issues
|
|
13
|
+
Requires-Python: >=3.12
|
|
14
|
+
Provides-Extra: sdl3
|
|
15
|
+
Requires-Dist: pysdl3; extra == "sdl3"
|
|
16
|
+
Provides-Extra: metal
|
|
17
|
+
Requires-Dist: pysdl3; extra == "metal"
|
|
18
|
+
Requires-Dist: pyobjc-framework-Metal; sys_platform == "darwin" and extra == "metal"
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# imgui
|
|
22
|
+
|
|
23
|
+
Python bindings for [Dear ImGui](https://github.com/ocornut/imgui) (v1.93.0, docking branch), its
|
|
24
|
+
SDL3 platform backend, its SDL_GPU, OpenGL 3 and Vulkan renderer backends, on Windows its Direct3D 12
|
|
25
|
+
renderer backend, on macOS its Metal and Metal 4 renderer backends, [ImPlot](https://github.com/epezent/implot) and
|
|
26
|
+
[ImGuizmo](https://github.com/CedricGuillemet/ImGuizmo). The bindings are generated
|
|
27
|
+
with [litgen](https://pthom.github.io/litgen/) from the unmodified upstream headers and built with
|
|
28
|
+
nanobind. Windows, GPU devices and events come from
|
|
29
|
+
[pysdl3](https://github.com/Aermoss/PySDL3).
|
|
30
|
+
|
|
31
|
+
```python
|
|
32
|
+
import imgui
|
|
33
|
+
from imgui import impl_sdl3, impl_sdlgpu3
|
|
34
|
+
|
|
35
|
+
imgui.create_context()
|
|
36
|
+
impl_sdl3.init_for_sdl_gpu(window) # pysdl3's window and GPU device
|
|
37
|
+
impl_sdlgpu3.init(impl_sdlgpu3.InitInfo(device=gpu_device, color_target_format=swapchain_format))
|
|
38
|
+
...
|
|
39
|
+
impl_sdl3.process_event(event) # pysdl3's SDL_Event
|
|
40
|
+
impl_sdlgpu3.new_frame()
|
|
41
|
+
impl_sdl3.new_frame()
|
|
42
|
+
imgui.new_frame()
|
|
43
|
+
if imgui.begin("Hello")[0]:
|
|
44
|
+
changed, value = imgui.slider_float("Value", value, 0.0, 1.0)
|
|
45
|
+
imgui.end()
|
|
46
|
+
imgui.render()
|
|
47
|
+
draw_data = imgui.get_draw_data()
|
|
48
|
+
impl_sdlgpu3.prepare_draw_data(draw_data, command_buffer) # before the render pass
|
|
49
|
+
impl_sdlgpu3.render_draw_data(draw_data, command_buffer, render_pass)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The full program is [src/imgui/app.py](src/imgui/app.py): `imgui.app.run()` sets all of this up
|
|
53
|
+
on Metal, Vulkan or Direct3D 12, and calls a function to build the GUI of every frame:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
import imgui
|
|
57
|
+
from imgui import app
|
|
58
|
+
|
|
59
|
+
def gui():
|
|
60
|
+
imgui.text(f"Drawn with {app.context().backend.name}")
|
|
61
|
+
|
|
62
|
+
app.run(gui, window_title="Hello", window_size=(1280, 720), fps_idle=0,
|
|
63
|
+
backends=(app.Backend.vulkan, app.Backend.metal)) # by default, SDL's choice
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`backends` lists the SDL_GPU drivers in order of preference. `app.context()` holds the window
|
|
67
|
+
and the GPU device, and `app.context().app_shall_exit = True` closes the window.
|
|
68
|
+
|
|
69
|
+
### OpenGL 3
|
|
70
|
+
|
|
71
|
+
`imgui.impl_opengl3` binds `imgui_impl_opengl3.h`, whose textures are GL texture names:
|
|
72
|
+
`imgui.image(imgui.ImTextureRef(texture), size)` takes the `GLuint`. The extension does not link
|
|
73
|
+
OpenGL: the backend opens the system's OpenGL library when `impl_opengl3.init()` runs, and calls it
|
|
74
|
+
in the GL context that is current. [src/imgui/app_opengl3.py](src/imgui/app_opengl3.py) is `run()` for
|
|
75
|
+
SDL3 and OpenGL, which creates a core profile context (3.2 by default, `gl_version=` for another)
|
|
76
|
+
and keeps it current while the GUI is built, so that any GL binding (PyOpenGL, moderngl...) can
|
|
77
|
+
draw into textures for it:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from imgui import app_opengl3
|
|
81
|
+
|
|
82
|
+
def gui():
|
|
83
|
+
imgui.image(imgui.ImTextureRef(texture), (512, 512)) # a GLuint of app_opengl3's context
|
|
84
|
+
|
|
85
|
+
app_opengl3.run(gui, window_title="Hello", post_init=create_textures)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`app_opengl3.context()` holds the window and the `SDL_GLContext`.
|
|
89
|
+
|
|
90
|
+
### Vulkan
|
|
91
|
+
|
|
92
|
+
`imgui.impl_vulkan` binds `imgui_impl_vulkan.h`. Its handles are ints (addresses), ctypes objects
|
|
93
|
+
or anything that `int()` converts (cffi's pointers, as the `vulkan` package has them), and
|
|
94
|
+
`impl_vulkan.InitInfo` and `impl_vulkan.PipelineInfo` take their fields as keyword arguments. Textures
|
|
95
|
+
are descriptor sets: `imgui.image(imgui.ImTextureRef(impl_vulkan.add_texture(view, layout)), size)`.
|
|
96
|
+
The extension does not link Vulkan: `impl_vulkan.init()` looks the backend's functions up through
|
|
97
|
+
the `vkGetInstanceProcAddr` of the Vulkan library that SDL3 loaded (for a window with
|
|
98
|
+
`SDL_WINDOW_VULKAN`), unless `impl_vulkan.load_functions()` was given another one.
|
|
99
|
+
[src/imgui/app_vulkan.py](src/imgui/app_vulkan.py) is `run()` for SDL3 and Vulkan 1.3, which it
|
|
100
|
+
calls through ctypes, and draws with dynamic rendering:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from imgui import app_vulkan, impl_vulkan
|
|
104
|
+
|
|
105
|
+
def gui():
|
|
106
|
+
context = app_vulkan.context() # the window, VkInstance, VkDevice, VkQueue, ...
|
|
107
|
+
context.keep_alive(texture) # until the GPU is done with this frame
|
|
108
|
+
imgui.image(imgui.ImTextureRef(descriptor_set), (512, 512)) # of impl_vulkan.add_texture()
|
|
109
|
+
|
|
110
|
+
app_vulkan.run(gui, window_title="Hello", device_extensions=["VK_KHR_external_memory_win32"])
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
`context()` holds the handles as ints, and the address of `vkGetInstanceProcAddr` to load further
|
|
114
|
+
functions with. `device_extensions` and `instance_extensions` enable extensions beyond the swapchain's,
|
|
115
|
+
e.g. to share memory with another API, and `validation=True` enables the Khronos validation layer.
|
|
116
|
+
|
|
117
|
+
### Direct3D 12 (Windows)
|
|
118
|
+
|
|
119
|
+
On Windows, `imgui.impl_dx12` binds `imgui_impl_dx12.h`. Its objects are ints (addresses) or ctypes
|
|
120
|
+
pointers (comtypes' as well), and descriptor handles are the ints of their `ptr`. The backend takes the
|
|
121
|
+
SRV descriptors of its textures from the application, through the Python functions
|
|
122
|
+
`srv_descriptor_alloc_fn` (returning a `(cpu_handle, gpu_handle)` pair) and `srv_descriptor_free_fn`
|
|
123
|
+
of `impl_dx12.InitInfo`. The texture of `imgui.image()` is the GPU handle of an SRV in the same
|
|
124
|
+
heap. [src/imgui/app_dx12.py](src/imgui/app_dx12.py) is `run()` for SDL3 and Direct3D 12, which
|
|
125
|
+
it calls through ctypes, and hands out the descriptors of its heap:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from imgui import app_dx12
|
|
129
|
+
|
|
130
|
+
srv = {}
|
|
131
|
+
|
|
132
|
+
def post_init():
|
|
133
|
+
srv["cpu"], srv["gpu"] = app_dx12.context().allocate_srv_descriptor()
|
|
134
|
+
... # ID3D12Device::CreateShaderResourceView(texture, ..., srv["cpu"])
|
|
135
|
+
|
|
136
|
+
def gui():
|
|
137
|
+
imgui.image(imgui.ImTextureRef(srv["gpu"]), (512, 512))
|
|
138
|
+
|
|
139
|
+
app_dx12.run(gui, window_title="Hello", post_init=post_init, device=device) # by default, its own device
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`context()` holds the window, the `ID3D12Device`, the `ID3D12CommandQueue` and the descriptor
|
|
143
|
+
heap, as ints, and `validation=True` enables the debug layer, whose messages are printed.
|
|
144
|
+
|
|
145
|
+
### Metal and Metal 4 (macOS)
|
|
146
|
+
|
|
147
|
+
On macOS, `imgui.impl_metal` and `imgui.impl_metal4` bind `imgui_impl_metal.h` and
|
|
148
|
+
`imgui_impl_metal4.h`. Their Metal objects are
|
|
149
|
+
[PyObjC](https://pyobjc.readthedocs.io)'s (the `metal` extra installs `pyobjc-framework-Metal`),
|
|
150
|
+
ctypes pointers or addresses; `texture_id(texture)` gives the `ImTextureID` of any `MTLTexture`.
|
|
151
|
+
[src/imgui/app_metal4.py](src/imgui/app_metal4.py) is `run()` for SDL3 and Metal 4, which also takes
|
|
152
|
+
the `MTLDevice` to draw with:
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from imgui import app_metal4, impl_metal4
|
|
156
|
+
|
|
157
|
+
def gui():
|
|
158
|
+
context = app_metal4.context() # the window, MTLDevice, MTL4CommandQueue, ...
|
|
159
|
+
context.keep_alive(texture) # until the GPU is done with this frame
|
|
160
|
+
imgui.image(imgui.ImTextureRef(impl_metal4.texture_id(texture)), (512, 512))
|
|
161
|
+
|
|
162
|
+
app_metal4.run(gui, window_title="Hello", device=device) # by default, the system's device
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
The GUI can so show textures that view the memory of another library on the same device, e.g. a
|
|
166
|
+
GPU array's buffer (`MTLBuffer.newTextureWithDescriptor:offset:bytesPerRow:`). Metal 4 queues do not
|
|
167
|
+
track hazards: the queue has to wait for the other library's work (`context().command_queue
|
|
168
|
+
.waitForEvent_value_()`), the memory has to stay alive while frames draw it (`keep_alive()`), and the
|
|
169
|
+
buffers behind views belong in `context().residency_set`. The backend adds every texture that it draws
|
|
170
|
+
to a residency set of its own, which retains it: `impl_metal4.forget_texture()` removes one that is
|
|
171
|
+
no longer drawn.
|
|
172
|
+
|
|
173
|
+
## Installing
|
|
174
|
+
|
|
175
|
+
PyPI has wheels for Python 3.12+ on Windows and Linux (glibc 2.34+), on x86-64 and ARM64, and on macOS 26+
|
|
176
|
+
on Apple silicon. Running needs pysdl3, which the `sdl3` extra installs (its SDL3 is what needs macOS 26).
|
|
177
|
+
|
|
178
|
+
```sh
|
|
179
|
+
pip install "PyImGui[sdl3]" # or: uv pip install "PyImGui[sdl3]"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Building from source needs a C++17 compiler and CMake. CMake downloads Dear ImGui, ImPlot, ImGuizmo
|
|
183
|
+
and the headers of SDL3 and Vulkan, which are not built or linked; on Windows, it also downloads the SDL3 import
|
|
184
|
+
library to link against.
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
pip install ".[sdl3]" # in the repository's root
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
On macOS, the Metal backends need PyObjC's Metal bindings, which the `metal` extra adds:
|
|
191
|
+
`pip install ".[metal]"`.
|
|
192
|
+
|
|
193
|
+
## The Python API
|
|
194
|
+
|
|
195
|
+
The module follows these conventions:
|
|
196
|
+
|
|
197
|
+
- `ImGui::BeginTable()` is `imgui.begin_table()`, `ImGuiWindowFlags_NoResize` is
|
|
198
|
+
`imgui.WindowFlags_.no_resize`, `ImGuiIO` is `imgui.IO`.
|
|
199
|
+
- Functions that modify their pointer arguments return the new values instead:
|
|
200
|
+
`changed, v = imgui.checkbox("On", v)`, `visible, p_open = imgui.begin("Window", p_open)`.
|
|
201
|
+
- Tuples and lists work wherever an `ImVec2` or `ImVec4` is expected, and `ImVec2`/`ImVec4`
|
|
202
|
+
support arithmetic, indexing and unpacking.
|
|
203
|
+
- Strings are Python strings, `imgui.input_text("Name", name)` included.
|
|
204
|
+
- `io.ini_filename` sets or (with `None`) disables the settings file.
|
|
205
|
+
- The colors of a style are indexed by its `Col_` enum: `style.colors[imgui.Col_.text] = (1, 1, 1, 1)`.
|
|
206
|
+
The same goes for `implot.Style` and `imguizmo.Style`.
|
|
207
|
+
- The backends are the submodules `imgui.impl_sdl3`, `imgui.impl_sdlgpu3`, `imgui.impl_opengl3`,
|
|
208
|
+
`imgui.impl_vulkan` and, on Windows, `imgui.impl_dx12`:
|
|
209
|
+
`ImGui_ImplSDL3_ProcessEvent()` is `imgui.impl_sdl3.process_event()`. ImPlot and ImGuizmo are
|
|
210
|
+
`imgui.implot` and `imgui.imguizmo` (see below).
|
|
211
|
+
|
|
212
|
+
SDL objects are passed as pysdl3 creates them: its pointers (`SDL_Window*`, `SDL_GPUDevice*`,
|
|
213
|
+
...), its `SDL_Event`, `ctypes.byref()` of one, or plain addresses. SDL's enums are ints, as
|
|
214
|
+
in pysdl3.
|
|
215
|
+
|
|
216
|
+
Textures are passed to `imgui.image()` and similar functions as `imgui.ImTextureRef(id)`. The `id`
|
|
217
|
+
is the address of the `SDL_GPUTexture` (`ctypes.cast(texture, ctypes.c_void_p).value`).
|
|
218
|
+
|
|
219
|
+
Dear ImGui's assertions raise a `RuntimeError`. This covers the API misuse it checks for, such as a
|
|
220
|
+
missing `end()`. To recover from those errors in the running app instead, set
|
|
221
|
+
`io.config_error_recovery_enable_assert = False`.
|
|
222
|
+
|
|
223
|
+
The extension does not link SDL3 (except on Windows). Its SDL functions are looked up when
|
|
224
|
+
`import imgui` loads it, in the SDL3 library that pysdl3 ships, which `import imgui` imports and
|
|
225
|
+
exposes first. The backends and pysdl3 thus share one SDL3, so the windows and events that pysdl3
|
|
226
|
+
creates are the backends' own. That library has to be SDL 3.4.16 or newer, the release whose headers
|
|
227
|
+
the extension is compiled against (`SDL3_VERSION` in [CMakeLists.txt](CMakeLists.txt)).
|
|
228
|
+
|
|
229
|
+
Not bound: C callbacks (`InputText` and size-constraint callbacks, `ImDrawList.add_callback`,
|
|
230
|
+
ImPlot's getters, formatters and transforms), drag-and-drop payloads, the memory allocators, the
|
|
231
|
+
`va_list` variants of the text functions, the manual gamepad mode of the SDL3 backend, the per-point
|
|
232
|
+
color and size arrays of `implot.Spec`, the row and column ratios of `implot.begin_subplots()`,
|
|
233
|
+
ImGuizmo's other widgets (ImSequencer, ImCurveEdit...), and the internal headers.
|
|
234
|
+
|
|
235
|
+
## ImPlot and ImGuizmo
|
|
236
|
+
|
|
237
|
+
```python
|
|
238
|
+
import math
|
|
239
|
+
import numpy as np
|
|
240
|
+
import imgui
|
|
241
|
+
from imgui import app, imguizmo, implot
|
|
242
|
+
|
|
243
|
+
xs = np.linspace(0, 10, 200)
|
|
244
|
+
model = np.eye(4, dtype=np.float32) # modified in place by the gizmo, hence float32
|
|
245
|
+
view = np.eye(4, dtype=np.float32)
|
|
246
|
+
view[2, 3] = -5 # camera 5 units back, looking down -z
|
|
247
|
+
f, near, far = 1 / math.tan(math.radians(22.5)), 0.1, 100.0
|
|
248
|
+
projection = np.array([[f / 16 * 9, 0, 0, 0], [0, f, 0, 0], # OpenGL's perspective, 16:9
|
|
249
|
+
[0, 0, (far + near) / (near - far), 2 * far * near / (near - far)],
|
|
250
|
+
[0, 0, -1, 0]])
|
|
251
|
+
|
|
252
|
+
def gui():
|
|
253
|
+
imguizmo.begin_frame()
|
|
254
|
+
imgui.begin("Plot")
|
|
255
|
+
if implot.begin_plot("Waves"):
|
|
256
|
+
implot.plot_line("sin", xs, np.sin(xs), implot.Spec(line_weight=2, marker=implot.Marker_.circle))
|
|
257
|
+
implot.plot_bars("bars", np.arange(5))
|
|
258
|
+
implot.end_plot()
|
|
259
|
+
imgui.end()
|
|
260
|
+
size = imgui.get_io().display_size
|
|
261
|
+
imguizmo.set_rect(0, 0, size.x, size.y)
|
|
262
|
+
imguizmo.manipulate(view, projection, imguizmo.OPERATION.translate | imguizmo.OPERATION.rotate,
|
|
263
|
+
imguizmo.MODE.world, model)
|
|
264
|
+
|
|
265
|
+
app.run(gui, window_size=(1280, 720))
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
- ImPlot needs a context of its own, which `app.run()` creates. Elsewhere, call
|
|
269
|
+
`implot.create_context()` after `imgui.create_context()`.
|
|
270
|
+
- The plotting functions take numpy arrays (or any array with DLPack or the buffer protocol) of any
|
|
271
|
+
integer or floating-point type. The arrays of one call share a type and are 1D and contiguous,
|
|
272
|
+
except for `plot_heatmap()` and `plot_bar_groups()`, which take a 2D array. `implot.Spec` holds
|
|
273
|
+
the style of an item, and takes its fields as keyword arguments. `ImPlotPoint` is
|
|
274
|
+
`implot.Point`, for which tuples work as well.
|
|
275
|
+
- `imguizmo.begin_frame()` starts each frame, after `imgui.new_frame()`. Matrices are 4x4 arrays
|
|
276
|
+
indexed `[row, column]`, whatever their memory order: the translation of a model matrix is
|
|
277
|
+
`matrix[:3, 3]`, and vectors are multiplied from the right, as in OpenGL. The functions that
|
|
278
|
+
modify a matrix (`manipulate()`, `view_manipulate()`, `recompose_matrix_from_components()`) write
|
|
279
|
+
it back into the array, which must be float32. The others take any numeric type.
|
|
280
|
+
|
|
281
|
+
## Layout and regenerating the bindings
|
|
282
|
+
|
|
283
|
+
- `CMakeLists.txt` pins the Dear ImGui release (`IMGUI_GIT_TAG`), the ImPlot and ImGuizmo commits
|
|
284
|
+
(`IMPLOT_GIT_TAG`, `IMGUIZMO_GIT_TAG`) and the Vulkan headers (`VULKAN_HEADERS_GIT_TAG`), and
|
|
285
|
+
builds the single extension `imgui._imgui`, which holds them, the backends and all the bindings. They have to live in one extension because Dear
|
|
286
|
+
ImGui keeps its state in globals.
|
|
287
|
+
- `.github/workflows/wheels.yml` builds the wheels with cibuildwheel (options in `pyproject.toml`),
|
|
288
|
+
and uploads them to PyPI when a GitHub release is published. Bump `version` in `pyproject.toml`
|
|
289
|
+
first: the release tag has to match it (`v0.2.0` for `0.2.0`).
|
|
290
|
+
- `generate.py` holds the litgen options, and writes the code between the litgen markers of
|
|
291
|
+
`src/bindings/*.cpp` and `src/imgui/*.pyi`. The code outside those markers is written by hand:
|
|
292
|
+
the module definition, the Metal backends' bindings (`imgui_impl_metal_bindings.mm`, whose
|
|
293
|
+
Objective-C headers litgen cannot parse), the Vulkan and Direct3D 12 backends' bindings
|
|
294
|
+
(`imgui_impl_vulkan_bindings.cpp`, `imgui_impl_dx12_bindings.cpp`, whose structs hold native
|
|
295
|
+
structs and C callbacks), the SDL casters in `sdl3_casters.h`, the casters of native GPU handles
|
|
296
|
+
in `native_casters.h`, the opaque `Context` handles, the
|
|
297
|
+
`IM_ASSERT` of `imgui_config.h`, the ImGuizmo functions that take matrices, and the ImPlot
|
|
298
|
+
functions that take 2D arrays or labels.
|
|
299
|
+
|
|
300
|
+
The generated code is checked in, so building does not need litgen. After changing the options or
|
|
301
|
+
a pinned release, regenerate it with:
|
|
302
|
+
|
|
303
|
+
```sh
|
|
304
|
+
uv run generate.py # or: pip install litgen && python generate.py
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT ([LICENSE](LICENSE)); the code that litgen generates is not subject to litgen's GPL. The wheels
|
|
310
|
+
also contain Dear ImGui with its fonts, ImPlot, ImGuizmo and nanobind, whose licenses are in
|
|
311
|
+
[THIRD_PARTY_LICENSES.txt](THIRD_PARTY_LICENSES.txt).
|