Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
[submodule "imgui-cpp"]
path = imgui-cpp
url = https://github.com/ocornut/imgui.git

[submodule "implot-cpp"]
path = implot-cpp
url = https://github.com/epezent/implot.git
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@ recursive-include imgui-cpp *.cpp *.h
prune imgui-cpp/examples
prune imgui-cpp/extra_fonts

# ImPlot sources
recursive-include implot-cpp *.cpp *.h

# ansifeed sources
recursive-include ansifeed-cpp *.cpp *.h
63 changes: 59 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![completion](https://img.shields.io/badge/completion-81%25%20%28373%20of%20458%29-blue.svg)](https://github.com/swistakm/pyimgui)
[![completion](https://img.shields.io/badge/completion-70%25%20%28518%20of%20735%29-blue.svg)](https://github.com/swistakm/pyimgui)
[![Coverage Status](https://coveralls.io/repos/github/swistakm/pyimgui/badge.svg?branch=master)](https://coveralls.io/github/swistakm/pyimgui?branch=master)
[![Documentation Status](https://readthedocs.org/projects/pyimgui/badge/?version=latest)](https://pyimgui.readthedocs.io/en/latest/?badge=latest)

Expand All @@ -16,10 +16,65 @@ Immediate Mode Graphical User Interface.

Documentation: [pyimgui.readthedocs.io](https://pyimgui.readthedocs.io/en/latest/index.html)

# ImPlot

This fork includes python bindings for the amazing
[ImPlot](https://github.com/ocornut/imgui), GPU accelerated plotting library for
[Dear ImGui](https://github.com/ocornut/imgui).


Warning: This is alpha quality code.

Have a look at the `doc/examples/integrations_glfw3_implot.py` that includes ImPlot
demo. Note that the demo was **NOT** ported to python yet.

It is not clear to me if this is the best place for ImPlot python binding. The
question remains if it would be better to place this code into a separate project,
or provide it as part of pyimgui. As of now the latter has been chosen due to my
laziness, poor undestanding of cython and also due to some obstacles
encountered during the process of creating this binding.

Read on if you are interested in couple of details.

As per ImGui and ImPlot documentation using them both as shared library is not recomended.
In case of python binding this is exactly what is being done. The ImGui part ends up being
a shared library and plot becomes a separate shared library. Creating a single shared library
(with ImGui and ImPlot) does not sound like a good idea at all so lets not go there. Not going
with shared library is also something that we can not do; AFAICT due to the way cypthon does
its business (I might be wrong).

At the level of C++ that cython wraps into python module and functions, ImPlot want access
to `imgui.h` and `imgui_internal.h`. For example ImPlot uses `ImTextureID`, `ImGuiCond`,
`ImGuiMouseButton`, `ImGuiKeyModFlags`, `ImGuiDragDropFlags`, `ImU32`, `ImDrawList`, `ImGuiContext`,
`ImVec2`, `ImVec4` and alike. These need to be exposed a cython level, too. Currently,
these come from `cimgui` and `internal` modules provided by pyimgui binding. Using them is
as simple as adding a `cimport` line to a `cimplot.pxd`. pyimgui (c)imports were requiered for
`plot.pyx` as well:

cimport cimplot
cimport cimgui
cimport core
cimport enums

If the ImPlot is placed in a separate project/repo these would need to be redefined.


When I tried to compile the ImPlot C++ code for cython binding (without adding ImGui sources)
for that shared library, doing `import imgui` in a user script fails with `GImGui` being undefined.
Have I missed something there during the library build?! I don't know.

If the ImPlot binding is separate from ImGui binding (cleanest approach), I'm not sure how
the user script would behave if pyimgui and pyimplot would be based of different ImGui C++ code.
Might be a non-issue, but I just do not know.

Have any ideas or suggestions on the above topics? Bring them up, please!



# Installation

**pyimgui** is available on PyPI so you can easily install it with `pip`:

pip install imgui[full]

Above command will install `imgui` package with additional dependencies for all
Expand Down Expand Up @@ -96,8 +151,8 @@ activated virtual environment using `virtualenv` or `python -m venv` (for newer
Python releases). Then you can just run:

make build
This command will bootstrap whole environment (pull git submodules, install

This command will bootstrap whole environment (pull git submodules, install
dev requirements etc.) and build the project. `make` will automatically install
`imgui` in the *development/editable* mode. Then you can run some examples
found in the `doc/examples` directory in order to verify if project is working.
Expand Down
92 changes: 92 additions & 0 deletions doc/examples/integrations_glfw3_implot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
import glfw
import OpenGL.GL as gl

import imgui
from imgui.integrations.glfw import GlfwRenderer
from testwindow import show_test_window

def main():
# imgui.create_context()
ctx = imgui.create_context()
imgui.plot.create_context()
imgui.plot.set_imgui_context(ctx)
window = impl_glfw_init()
impl = GlfwRenderer(window)

while not glfw.window_should_close(window):
glfw.poll_events()
impl.process_inputs()

imgui.new_frame()

if imgui.begin_main_menu_bar():
if imgui.begin_menu("File", True):

clicked_quit, selected_quit = imgui.menu_item(
"Quit", 'Cmd+Q', False, True
)

if clicked_quit:
exit(1)

imgui.end_menu()
imgui.end_main_menu_bar()


imgui.begin("Custom window", True)
imgui.text("Bar")
imgui.text_ansi("B\033[31marA\033[mnsi ")
imgui.text_ansi_colored("Eg\033[31mgAn\033[msi ", 0.2, 1., 0.)
imgui.extra.text_ansi_colored("Eggs", 0.2, 1., 0.)
imgui.end()

# XXX: not ready for prime time?
# show_test_window()
# ImGui demo
imgui.show_test_window()
# ImPlot demo
imgui.plot.show_demo_window(True)

gl.glClearColor(1., 1., 1., 1)
gl.glClear(gl.GL_COLOR_BUFFER_BIT)

imgui.render()
impl.render(imgui.get_draw_data())
glfw.swap_buffers(window)

impl.shutdown()
glfw.terminate()


def impl_glfw_init():
width, height = 1280, 720
window_name = "minimal ImGui/GLFW3 example"

if not glfw.init():
print("Could not initialize OpenGL context")
exit(1)

# OS X supports only forward-compatible core profiles from 3.2
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)

glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, gl.GL_TRUE)

# Create a windowed mode window and its OpenGL context
window = glfw.create_window(
int(width), int(height), window_name, None, None
)
glfw.make_context_current(window)

if not window:
glfw.terminate()
print("Could not initialize Window")
exit(1)

return window


if __name__ == "__main__":
main()
69 changes: 35 additions & 34 deletions imgui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from imgui import extra
from imgui import _compat
from imgui import internal
from imgui import plot

# TODO: Complete and correcte doc text for ImGui v1.79

Expand Down Expand Up @@ -61,7 +62,7 @@
KEY_ENTER = core.KEY_ENTER
#: for text edit
KEY_ESCAPE = core.KEY_ESCAPE
#:
#:
KEY_PAD_ENTER = core.KEY_PAD_ENTER
#: for text edit CTRL+A: select all
KEY_A = core.KEY_A
Expand Down Expand Up @@ -96,7 +97,7 @@
#: scroll / move window (w/ PadMenu) e.g. Left Analog Stick Left/Right/Up/Down
NAV_INPUT_L_STICK_LEFT = core.NAV_INPUT_L_STICK_LEFT
#:
NAV_INPUT_L_STICK_RIGHT = core.NAV_INPUT_L_STICK_RIGHT
NAV_INPUT_L_STICK_RIGHT = core.NAV_INPUT_L_STICK_RIGHT
#:
NAV_INPUT_L_STICK_UP = core.NAV_INPUT_L_STICK_UP
#:
Expand Down Expand Up @@ -370,10 +371,10 @@
COLOR_RESIZE_GRIP_HOVERED = core.COLOR_RESIZE_GRIP_HOVERED
COLOR_RESIZE_GRIP_ACTIVE = core.COLOR_RESIZE_GRIP_ACTIVE
COLOR_TAB = COLOR_TAB
COLOR_TAB_HOVERED = COLOR_TAB_HOVERED
COLOR_TAB_ACTIVE = COLOR_TAB_ACTIVE
COLOR_TAB_UNFOCUSED = COLOR_TAB_UNFOCUSED
COLOR_TAB_UNFOCUSED_ACTIVE = COLOR_TAB_UNFOCUSED_ACTIVE
COLOR_TAB_HOVERED = COLOR_TAB_HOVERED
COLOR_TAB_ACTIVE = COLOR_TAB_ACTIVE
COLOR_TAB_UNFOCUSED = COLOR_TAB_UNFOCUSED
COLOR_TAB_UNFOCUSED_ACTIVE = COLOR_TAB_UNFOCUSED_ACTIVE
COLOR_PLOT_LINES = core.COLOR_PLOT_LINES
COLOR_PLOT_LINES_HOVERED = core.COLOR_PLOT_LINES_HOVERED
COLOR_PLOT_HISTOGRAM = core.COLOR_PLOT_HISTOGRAM
Expand All @@ -392,15 +393,15 @@
COLOR_COUNT = core.COLOR_COUNT

# === Data Type (redefines for autodoc)
DATA_TYPE_S8 = core.DATA_TYPE_S8
DATA_TYPE_U8 = core.DATA_TYPE_U8
DATA_TYPE_S16 = core.DATA_TYPE_S16
DATA_TYPE_U16 = core.DATA_TYPE_U16
DATA_TYPE_S32 = core.DATA_TYPE_S32
DATA_TYPE_U32 = core.DATA_TYPE_U32
DATA_TYPE_S64 = core.DATA_TYPE_S64
DATA_TYPE_U64 = core.DATA_TYPE_U64
DATA_TYPE_FLOAT = core.DATA_TYPE_FLOAT
DATA_TYPE_S8 = core.DATA_TYPE_S8
DATA_TYPE_U8 = core.DATA_TYPE_U8
DATA_TYPE_S16 = core.DATA_TYPE_S16
DATA_TYPE_U16 = core.DATA_TYPE_U16
DATA_TYPE_S32 = core.DATA_TYPE_S32
DATA_TYPE_U32 = core.DATA_TYPE_U32
DATA_TYPE_S64 = core.DATA_TYPE_S64
DATA_TYPE_U64 = core.DATA_TYPE_U64
DATA_TYPE_FLOAT = core.DATA_TYPE_FLOAT
DATA_TYPE_DOUBLE = core.DATA_TYPE_DOUBLE


Expand Down Expand Up @@ -551,7 +552,7 @@
TABLE_NO_PAD_INNER_X = core.TABLE_NO_PAD_INNER_X
#: # Scrolling
#: Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX.
TABLE_SCROLL_X = core.TABLE_SCROLL_X
TABLE_SCROLL_X = core.TABLE_SCROLL_X
#: Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
TABLE_SCROLL_Y = core.TABLE_SCROLL_Y
#: # Sorting
Expand Down Expand Up @@ -707,7 +708,7 @@
DIRECTION_DOWN = core.DIRECTION_DOWN

# === Sorting direction
SORT_DIRECTION_NONE = core.SORT_DIRECTION_NONE
SORT_DIRECTION_NONE = core.SORT_DIRECTION_NONE
#: Ascending = 0->9, A->Z etc.
SORT_DIRECTION_ASCENDING = core.SORT_DIRECTION_ASCENDING
#: Descending = 9->0, Z->A etc.
Expand Down Expand Up @@ -796,27 +797,27 @@
#: None
DRAW_NONE = core.DRAW_NONE
#: path_stroke(), add_polyline(): specify that shape should be closed (Important: this is always == 1 for legacy reason)
DRAW_CLOSED = core.DRAW_CLOSED
DRAW_CLOSED = core.DRAW_CLOSED
#: add_rect(), add_rect_filled(), path_rect(): enable rounding top-left corner only (when rounding > 0.0f, we default to all corners). Was 0x01.
DRAW_ROUND_CORNERS_TOP_LEFT = core.DRAW_ROUND_CORNERS_TOP_LEFT
DRAW_ROUND_CORNERS_TOP_LEFT = core.DRAW_ROUND_CORNERS_TOP_LEFT
#: add_rect(), add_rect_filled(), path_rect(): enable rounding top-right corner only (when rounding > 0.0f, we default to all corners). Was 0x02.
DRAW_ROUND_CORNERS_TOP_RIGHT = core.DRAW_ROUND_CORNERS_TOP_RIGHT
DRAW_ROUND_CORNERS_TOP_RIGHT = core.DRAW_ROUND_CORNERS_TOP_RIGHT
#: add_rect(), add_rect_filled(), path_rect(): enable rounding bottom-left corner only (when rounding > 0.0f, we default to all corners). Was 0x04.
DRAW_ROUND_CORNERS_BOTTOM_LEFT = core.DRAW_ROUND_CORNERS_BOTTOM_LEFT
DRAW_ROUND_CORNERS_BOTTOM_LEFT = core.DRAW_ROUND_CORNERS_BOTTOM_LEFT
#: add_rect(), add_rect_filled(), path_rect(): enable rounding bottom-right corner only (when rounding > 0.0f, we default to all corners). Wax 0x08.
DRAW_ROUND_CORNERS_BOTTOM_RIGHT = core.DRAW_ROUND_CORNERS_BOTTOM_RIGHT
DRAW_ROUND_CORNERS_BOTTOM_RIGHT = core.DRAW_ROUND_CORNERS_BOTTOM_RIGHT
#: add_rect(), add_rect_filled(), path_rect(): disable rounding on all corners (when rounding > 0.0f). This is NOT zero, NOT an implicit flag!
DRAW_ROUND_CORNERS_NONE = core.DRAW_ROUND_CORNERS_NONE
DRAW_ROUND_CORNERS_NONE = core.DRAW_ROUND_CORNERS_NONE
#: DRAW_ROUND_CORNERS_TOP_LEFT | DRAW_ROUND_CORNERS_TOP_RIGHT
DRAW_ROUND_CORNERS_TOP = core.DRAW_ROUND_CORNERS_TOP
DRAW_ROUND_CORNERS_TOP = core.DRAW_ROUND_CORNERS_TOP
#: DRAW_ROUND_CORNERS_BOTTOM_LEFT | DRAW_ROUND_CORNERS_BOTTOM_RIGHT
DRAW_ROUND_CORNERS_BOTTOM = core.DRAW_ROUND_CORNERS_BOTTOM
DRAW_ROUND_CORNERS_BOTTOM = core.DRAW_ROUND_CORNERS_BOTTOM
#: DRAW_ROUND_CORNERS_BOTTOM_LEFT | DRAW_ROUND_CORNERS_TOP_LEFT
DRAW_ROUND_CORNERS_LEFT = core.DRAW_ROUND_CORNERS_LEFT
DRAW_ROUND_CORNERS_LEFT = core.DRAW_ROUND_CORNERS_LEFT
#: DRAW_ROUND_CORNERS_BOTTOM_RIGHT | DRAW_ROUND_CORNERS_TOP_RIGHT
DRAW_ROUND_CORNERS_RIGHT = core.DRAW_ROUND_CORNERS_RIGHT
DRAW_ROUND_CORNERS_RIGHT = core.DRAW_ROUND_CORNERS_RIGHT
#: DRAW_ROUND_CORNERS_TOP_LEFT | DRAW_ROUND_CORNERS_TOP_RIGHT | DRAW_ROUND_CORNERS_BOTTOM_LEFT | DRAW_ROUND_CORNERS_BOTTOM_RIGHT
DRAW_ROUND_CORNERS_ALL = core.DRAW_ROUND_CORNERS_ALL
DRAW_ROUND_CORNERS_ALL = core.DRAW_ROUND_CORNERS_ALL

# === Draw List Flags (redefines for autodoc)
DRAW_LIST_NONE = core.DRAW_LIST_NONE
Expand Down Expand Up @@ -852,18 +853,18 @@
# === Slider flag (redefines for autodoc)
SLIDER_FLAGS_NONE
#: Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
SLIDER_FLAGS_ALWAYS_CLAMP
SLIDER_FLAGS_ALWAYS_CLAMP
#: Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
SLIDER_FLAGS_LOGARITHMIC
SLIDER_FLAGS_LOGARITHMIC
#: Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
SLIDER_FLAGS_NO_ROUND_TO_FORMAT
SLIDER_FLAGS_NO_ROUND_TO_FORMAT
#: Disable CTRL+Click or Enter key allowing to input text directly into the widget
SLIDER_FLAGS_NO_INPUT
SLIDER_FLAGS_NO_INPUT

# === Mouse Button (redefines for autodoc)
MOUSE_BUTTON_LEFT = core.MOUSE_BUTTON_LEFT
MOUSE_BUTTON_RIGHT = core.MOUSE_BUTTON_RIGHT
MOUSE_BUTTON_MIDDLE = core.MOUSE_BUTTON_MIDDLE
MOUSE_BUTTON_MIDDLE = core.MOUSE_BUTTON_MIDDLE

# === Viewport Flags (redifines for autodoc)
#: None
Expand All @@ -873,5 +874,5 @@
#: Represent a Platform Monitor (unused yet)
VIEWPORT_FLAGS_IS_PLATFORM_MONITOR = core.VIEWPORT_FLAGS_IS_PLATFORM_MONITOR
#: Platform Window: is created/managed by the application (rather than a dear imgui backend)
VIEWPORT_FLAGS_OWNED_BY_APP = core.VIEWPORT_FLAGS_OWNED_BY_APP
VIEWPORT_FLAGS_OWNED_BY_APP = core.VIEWPORT_FLAGS_OWNED_BY_APP

Loading