Usage instructions

Dear ImGui - Immediate GUI

Dear ImGui is an implementation of the Immediate Gui paradigm.

Dear ImGui demo (and manual)

Dear ImGui comes with a complete demo. It demonstrates all the widgets, together with an example code on how to use them.

Tip
To run this demo in your browser, launch ImGui Manual.

For each widget, you will see the corresponding demo code (in C++. Read the part "C++ / Python porting advices" to see how easy it is to translate Gui code from C++ to python.

Dear ImGui C++ API

Dear ImGui’s C++ API is thoroughly documented in its header files:

Dear ImGui Python API

The python API closely mirrors the C++ API, and its documentation is extremely easy to access from your IDE, via thoroughly documented stub (*.pyi) files.

Example

An example is often worth a thousand words, the following code:

C++

// Display a text
ImGui::Text("Counter = %i", app_state.counter);
ImGui::SameLine(); // by default ImGui starts a new line at each widget

// The following line displays a button
if (ImGui::Button("increment counter"))
    // And returns true if it was clicked: you can *immediately* handle the click
    app_state.counter += 1;

// Input a text: in C++, InputText returns a bool and modifies the text directly
bool changed = ImGui::InputText("Your name?", &app_state.name);
ImGui::Text("Hello %s!", app_state.name.c_str());

Python

# Display a text
imgui.text(f"Counter = {app_state.counter}")
imgui.same_line()  # by default ImGui starts a new line at each widget

# The following line displays a button
if imgui.button("increment counter"):
    # And returns true if it was clicked: you can *immediately* handle the click
    app_state.counter += 1

# Input a text: in python, input_text returns a tuple(modified, new_value)
changed, app_state.name = imgui.input_text("Your name?", app_state.name)
imgui.text(f"Hello {app_state.name}!")

Displays this:

immediate gui example

Hello ImGui - Starter pack

Dear ImGui Bundle includes Hello ImGui, which is itself based on ImGui. "Hello ImGui" can be compared to a starter pack that enables to easily write cross-platform Gui apps for Windows, macOS, Linux, iOS, and emscripten.

API & Usage

See the "Hello ImGui" API doc and Application parameter doc.

Features

Multiplatform utilities

  • Truly multiplatform: Linux, Windows, macOS, iOS, Android, emscripten (with 4 lines of CMake code)

  • Easily embed assets on all platforms (no code required)

  • Customize app settings (icon and app name for mobile platforms, etc.- no code required)

  • Customize application icon on all platforms (including mobile and macOS - no code required)

Dear ImGui Tweaks

  • Power Save mode: reduce FPS when idling

  • High DPI support: scale UI according to DPI, whatever the platform

  • Advanced layout handling: dockable windows, multiple layouts

  • Window geometry utilities: autosize application window, restore app window position

  • Theme tweaking: extensive list of additional themes

  • Support for movable and resizable borderless windows

  • Advanced font support: icons, emojis and colored fonts

  • Integration with ImGui Test Engine: automate and test your apps

  • Save user settings: window position, layout, opened windows, theme, user defined custom settings

  • Easily add a custom 3D background to your app

Backends

  • Available platform backends: SDL2, Glfw3

  • Available rendering backends: OpenGL3, Metal, Vulkan, DirectX

Note
The usage of Hello ImGui is optional. You can also build an imgui application from scratch, in C++ or in python (see python example)
Tip
HelloImGui is fully configurable by POD (plain old data) structures. See their description

Advanced layout and theming with Hello ImGui:

See the demo named "demo_docking", which demonstrates:

  • How to handle complex layouts: you can define several layouts and switch between them: each layout which will remember the user modifications and the list of opened windows

  • How to use theming

  • How to store you own user settings in the app ini file

  • How to add a status bar and a log window

  • How to reduce the FPS when idling (to reduce CPU usage)

Links:

ImmApp - Immediate App

ImGui Bundle includes a library named ImmApp (which stands for Immediate App). ImmApp is a thin extension of HelloImGui that enables to easily initialize the ImGuiBundle addons that require additional setup at startup

How to start an application with addons

Click to see an example application with addons

Some libraries included by ImGui Bundle require an initialization at startup. ImmApp makes this easy via AddOnParams.

The example program below demonstrates how to run an application which will use implot (which requires a context to be created at startup), and imgui_md (which requires additional fonts to be loaded at startup).

C++

#ifdef IMGUI_BUNDLE_WITH_IMPLOT
#include "immapp/immapp.h"
#include "imgui_md_wrapper/imgui_md_wrapper.h"
#include "implot/implot.h"
#include "demo_utils/api_demos.h"
#include <vector>
#include <cmath>


int main(int, char**)
{
    // This call is specific to the ImGui Bundle interactive manual. In a standard application, you could write:
    //         HelloImGui::SetAssetsFolder("my_assets"); // (By default, HelloImGui will search inside "assets")
    ChdirBesideAssetsFolder();

    constexpr double pi = 3.1415926535897932384626433;
    std::vector<double> x, y1, y2;
    for (double _x = 0; _x < 4 * pi; _x += 0.01)
    {
        x.push_back(_x);
        y1.push_back(std::cos(_x));
        y2.push_back(std::sin(_x));
    }

    auto gui = [x,y1,y2]()
    {
        ImGuiMd::Render("# This is the plot of _cosinus_ and *sinus*");  // Markdown
        if (ImPlot::BeginPlot("Plot"))
        {
            ImPlot::PlotLine("y1", x.data(), y1.data(), x.size());
            ImPlot::PlotLine("y2", x.data(), y2.data(), x.size());
            ImPlot::EndPlot();
        }
    };

    HelloImGui::SimpleRunnerParams runnerParams { .guiFunction = gui, .windowSize = {600, 400} };
    ImmApp::AddOnsParams addons { .withImplot = true, .withMarkdown = true };
    ImmApp::Run(runnerParams, addons);

    return 0;
}
#else // #ifdef IMGUI_BUNDLE_WITH_IMPLOT
#include <cstdio>
int main(int, char**) { std::printf("This demo requires ImPlot.\n"); }
#endif

Python:

import numpy as np
from imgui_bundle import implot, imgui_md, immapp
from imgui_bundle.demos_python import demo_utils


def main():
    # This call is specific to the ImGui Bundle interactive manual. In a standard application, you could write:
    #         hello_imgui.set_assets_folder("my_assets"); # (By default, HelloImGui will search inside "assets")
    demo_utils.set_hello_imgui_demo_assets_folder()

    x = np.arange(0, np.pi * 4, 0.01)
    y1 = np.cos(x)
    y2 = np.sin(x)

    def gui():
        imgui_md.render("# This is the plot of _cosinus_ and *sinus*")  # Markdown
        if implot.begin_plot("Plot"):
            implot.plot_line("y1", x, y1)
            implot.plot_line("y2", x, y2)
            implot.end_plot()

    immapp.run(gui, with_implot=True, with_markdown=True, window_size=(600, 400))


if __name__ == "__main__":
    main()

Application Settings

Settings location

By default, the settings are stored in a ini file whose named is derived from the window title (i.e. runnerParams.appWindowParams.windowTitle). This is convenient when developing, but not so much when deploying the app.

You can finely define where they are stored by filling runnerParams.iniFolderType and runnerParams.iniFilename.

runnerParams.iniFolderType

Choose between: CurrentFolder,AppUserConfigFolder, AppExecutableFolder,HomeFolder, TempFolder and DocumentsFolder.

Note
Note: AppUserConfigFolder corresponds to …​\[Username]\AppData\Roaming under Windows, ~/.config under Linux, ~/Library/Application Support under macOS or iOS

runnerParams.iniFilename

This will be the name of the ini file in which the settings will be stored. It can include a subfolder, in which case it will be created under the folder defined by runnerParams.iniFolderType.

Note: if left empty, the name of the ini file will be derived from appWindowParams.windowTitle.

Examples

Click to expand the examples

C++ example (extract from demo_docking.cpp)

    // By default, HelloImGui will save the settings in the current folder.
    // This is convenient when developing, but not so much when deploying the app.
    // You can tell HelloImGui to save the settings in a specific folder: choose between
    //         CurrentFolder
    //         AppUserConfigFolder
    //         AppExecutableFolder
    //         HomeFolder
    //         TempFolder
    //         DocumentsFolder
    //
    // Note: AppUserConfigFolder is:
    //         AppData under Windows (Example: C:\Users\[Username]\AppData\Roaming)
    //         ~/.config under Linux
    //         "~/Library/Application Support" under macOS or iOS
    runnerParams.iniFolderType = HelloImGui::IniFolderType::AppUserConfigFolder;

    // runnerParams.iniFilename: this will be the name of the ini file in which the settings
    // will be stored.
    // In this example, the subdirectory Docking_Demo will be created under the folder defined
    // by runnerParams.iniFolderType.
    //
    // Note: if iniFilename is left empty, the name of the ini file will be derived
    // from appWindowParams.windowTitle
    runnerParams.iniFilename = "Docking_Demo/Docking_demo.ini";

Python example (extract from demo_docking.py)

    # By default, HelloImGui will save the settings in the current folder.
    # This is convenient when developing, but not so much when deploying the app.
    # You can tell HelloImGui to save the settings in a specific folder: choose between
    #         current_folder
    #         app_user_config_folder
    #         app_executable_folder
    #         home_folder
    #         temp_folder
    #         documents_folder
    #
    # Note: app_user_config_folder is:
    #         AppData under Windows (Example: C:\Users\[Username]\AppData\Roaming)
    #         ~/.config under Linux
    #         "~/Library/Application Support" under macOS or iOS
    runner_params.ini_folder_type = hello_imgui.IniFolderType.app_user_config_folder

    # runnerParams.ini_filename: this will be the name of the ini file in which the settings
    # will be stored.
    # In this example, the subdirectory Docking_Demo will be created under the folder defined
    # by runnerParams.ini_folder_type.
    #
    # Note: if ini_filename is left empty, the name of the ini file will be derived
    # from app_window_params.window_title
    runner_params.ini_filename = "Docking_Demo/Docking_demo.ini"

Settings content

The settings file contains, standard ImGui settings (window position, size, etc.), as well as additional settings defined by HelloImGui:

  • Application status: app window location, opened windows, status bar settings, etc. See members named remember_xxx in the Hello Imgui API for a complete list.

  • Settings for each application layout (see video for an example)

Store custom settings

You may store additional user settings in the application settings. This is provided as a convenience only, and it is not intended to store large quantities of text data. See related doc for more details.

Python: alternative backends

HelloImGui and ImmApp use glfw as a default backend.

If you wish to use a different backend, it is possible to use sdl2 or pyglet, via pure python backends.

The python backends folder contains a set of python backends, that can be used as a replacement for the default glfw backend. This way you will have complete control on your application (they are inspired from pyimgui backends).

Note
In this case, you will not benefit from HelloImGui and ImmApp rapid development features (HighDPI support, layout management, automatic idling, etc…​).

Documentation

See documentation in the python backends folder.

Examples

Example with a pure python sdl2 backend (click to expand)
# An example of using Dear ImGui with SDL using a *full python* backend.
# This mode is inspired from [pyimgui](https://github.com/pyimgui/pyimgui) backends, and is still experimental.
#
# See full python backends implementations here:
# https://github.com/pthom/imgui_bundle/tree/main/bindings/imgui_bundle/python_backends

# You will need to install sdl2:
#    pip install pysdl2 pysdl2-dll

from imgui_bundle import imgui
from imgui_bundle.python_backends.sdl_backend import SDL2Renderer
import OpenGL.GL as gl  # type: ignore
from sdl2 import *  # type: ignore
import ctypes
import sys


class AppState:
    text: str = """Hello, World\nLorem ipsum, etc.\netc."""
    text2: str = "Ahh"


app_state = AppState()


def main():
    window, gl_context = impl_pysdl2_init()
    imgui.create_context()
    impl = SDL2Renderer(window)

    show_custom_window = True

    running = True
    event = SDL_Event()
    while running:
        while SDL_PollEvent(ctypes.byref(event)) != 0:
            if event.type == SDL_QUIT:
                running = False
                break
            impl.process_event(event)
        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:
                    sys.exit(0)

                imgui.end_menu()
            imgui.end_main_menu_bar()

        if show_custom_window:
            imgui.set_next_window_size((400, 400))
            is_expand, show_custom_window = imgui.begin("Custom window", True)
            if is_expand:
                imgui.text("Example Text")
                if imgui.button("Hello"):
                    print("World")
                _, app_state.text = imgui.input_text_multiline(
                    "Edit", app_state.text, imgui.ImVec2(200, 200)
                )
                _, app_state.text2 = imgui.input_text("Text2", app_state.text2)

                io = imgui.get_io()
                imgui.text(f"""
                Keyboard modifiers:
                    {io.key_ctrl=}
                    {io.key_alt=}
                    {io.key_shift=}
                    {io.key_super=}""")
            imgui.end()

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

        imgui.render()
        impl.render(imgui.get_draw_data())
        SDL_GL_SwapWindow(window)

    impl.shutdown()
    SDL_GL_DeleteContext(gl_context)
    SDL_DestroyWindow(window)
    SDL_Quit()


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

    if SDL_Init(SDL_INIT_EVERYTHING) < 0:
        print(
            "Error: SDL could not initialize! SDL Error: "
            + SDL_GetError().decode("utf-8")
        )
        sys.exit(1)

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24)
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8)
    SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1)
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1)
    SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 8)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1)
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)

    SDL_SetHint(SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK, b"1")
    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, b"1")

    window = SDL_CreateWindow(
        window_name.encode("utf-8"),
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        width,
        height,
        SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE,
    )

    if window is None:
        print(
            "Error: Window could not be created! SDL Error: "
            + SDL_GetError().decode("utf-8")
        )
        sys.exit(1)

    gl_context = SDL_GL_CreateContext(window)
    if gl_context is None:
        print(
            "Error: Cannot create OpenGL Context! SDL Error: "
            + SDL_GetError().decode("utf-8")
        )
        sys.exit(1)

    SDL_GL_MakeCurrent(window, gl_context)
    if SDL_GL_SetSwapInterval(1) < 0:
        print(
            "Warning: Unable to set VSync! SDL Error: " + SDL_GetError().decode("utf-8")
        )
        sys.exit(1)

    return window, gl_context


if __name__ == "__main__":
    main()
Example with a pure python glfw backend (click to expand)
# An example of using Dear ImGui with Glfw using a *full python* backend.
# This mode is inspired from [pyimgui](https://github.com/pyimgui/pyimgui) backends, and is still experimental.
#
# These examples also demonstrate how to use the markdown rendering feature of ImGui Bundle.
#
# See full python backends implementations here:
# https://github.com/pthom/imgui_bundle/tree/main/bindings/imgui_bundle/python_backends

from imgui_bundle.python_backends.glfw_backend import GlfwRenderer
import OpenGL.GL as gl  # type: ignore
from imgui_bundle import imgui, imgui_ctx
from imgui_bundle import imgui_md
import glfw  # type: ignore
import sys


class AppState:
    text: str = """Hello, World\nLorem ipsum, etc.\netc."""


app_state = AppState()


def init_fonts_and_markdown():
    # Note:
    # The way font are loaded in this example is a bit tricky.
    # We are not using imgui.backends.opengl3_XXX anywhere else, because the rendering is done via Python.
    #
    # Howver, we will here need to:
    #     - call imgui.backends.opengl3_init(glsl_version) at startup
    #     - call imgui.backends.opengl3_new_frame() after loading the fonts, because this is how ImGui
    #       will load the fonts into a texture (using imgui.get_io().fonts.build() is not enough)

    # We need to initialize the OpenGL backend (so that we can later call opengl3_new_frame)
    imgui.backends.opengl3_init("#version 100")

    imgui.get_io().fonts.clear()
    # uncomment to keep using the default hardcoded font, or load your default font here
    # imgui.get_io().fonts.add_font_default()

    # Load markdown fonts
    imgui_md.initialize_markdown()
    font_loader = imgui_md.get_font_loader_function()
    font_loader()

    # We need to call this function to load the fonts into a texture
    imgui.backends.opengl3_new_frame()


def main():
    imgui.create_context()
    window = impl_glfw_init()
    impl = GlfwRenderer(window)
    init_fonts_and_markdown()

    show_custom_window = True
    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:
                    sys.exit(0)

                imgui.end_menu()
            imgui.end_main_menu_bar()

        if show_custom_window:
            imgui.set_next_window_size((400, 400))

            is_expand, show_custom_window = imgui.begin("Custom window", True)
            if is_expand:
                imgui_md.render_unindented("""
                # Hello, World
                Here is some *markdown* text.
                """)

                imgui.text("Example Text")
                if imgui.button("Hello"):
                    print("World")
                _, app_state.text = imgui.input_text_multiline(
                    "Edit", app_state.text, imgui.ImVec2(200, 200)
                )
                io = imgui.get_io()
                imgui.text(f"""
                Keyboard modifiers:
                    {io.key_ctrl=}
                    {io.key_alt=}
                    {io.key_shift=}
                    {io.key_super=}""")

                if imgui.button("Open popup"):
                    imgui.open_popup("my popup")
                with imgui_ctx.begin_popup_modal("my popup") as popup:
                    if popup.visible:
                        imgui.text("Hello from popup!")
                        if imgui.button("Close popup"):
                            imgui.close_current_popup()

            imgui.end()

        gl.glClearColor(1.0, 1.0, 1.0, 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")
        sys.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")
        sys.exit(1)

    return window


if __name__ == "__main__":
    main()

Usage within jupyter notebook

ImmApp adds support for integration inside jupyter notebook: the application will be run in an external window, and a screenshot will be placed on the notebook after execution.

This requires a window server, and will not run on Google collab.

Below is a screenshot, that you can test by running jupyter notebook inside bindings/imgui_bundle/demos_python/notebooks

immapp notebook example
Figure 20. Using ImGui Bundle inside Jupyter Notebook