pthom / hello_imgui

Hello, Dear ImGui: unleash your creativity in app development and prototyping
https://pthom.github.io/hello_imgui
MIT License
676 stars 103 forks source link

glfw callback chaincalls #27

Closed dcnieho closed 1 year ago

dcnieho commented 1 year ago

I am trying to add my own callbacks to hello_imgui's glfw window. There is an order issue here however. I've been modifying the heart haiku, this is the state i am in now. With this, any mouse click interaction with the gui is not possible, mouse clicks are not received. This is not strange, since the glfw backend's callback has been replaced by mine.

import time
import numpy as np

from imgui_bundle import implot, imgui_knobs, imgui, immapp, hello_imgui, glfw_window_hello_imgui
import glfw

# Fill x and y whose plot is a heart
vals = np.arange(0, np.pi * 2, 0.01)
x = np.power(np.sin(vals), 3) * 16
y = 13 * np.cos(vals) - 5 * np.cos(2 * vals) - 2 * np.cos(3 * vals) - np.cos(4 * vals)
# Heart pulse rate and time tracking
phase = 0
t0 = time.time() + 0.2
heart_pulse_rate = 80

def gui():
    global heart_pulse_rate, phase, t0, x, y
    # Make sure that the animation is smooth
    #hello_imgui.get_runner_params().fps_idling.enable_idling = False

    t = time.time()
    phase += (t - t0) * heart_pulse_rate / (np.pi * 2)
    k = 0.8 + 0.1 * np.cos(phase)
    t0 = t

    imgui.text("Bloat free code")
    implot.begin_plot("Heart", immapp.em_to_vec2(21, 21))
    implot.plot_line("", x * k, y * k)
    implot.end_plot()

    _, heart_pulse_rate = imgui_knobs.knob("Pulse", heart_pulse_rate, 30, 180)

def post_init():
    print(hello_imgui.get_runner_params().backend_pointers.glfw_window)
    #print(hello_imgui.get_glfw_window())
    print(glfw_window_hello_imgui())

    window = glfw_window_hello_imgui()

    # define a callback
    def my_window_size_callback(window: glfw._GLFWwindow, w: int, h: int):
        print(f"Window size changed to {w}x{h}")
    def my_mouse_button_callback(window: glfw._GLFWwindow, w: int, h: int, c: int):
        print(f"Mouse button")

    glfw.set_window_size_callback(window, my_window_size_callback)
    glfw.set_mouse_button_callback(window, my_mouse_button_callback)

if __name__ == "__main__":

    params = hello_imgui.RunnerParams()
    params.app_window_params.window_geometry.size = (300,450)
    params.app_window_params.window_title = window_title="Hello!"
    params.fps_idling.fps_idle = 0
    params.callbacks.show_gui = gui
    params.callbacks.post_init = post_init

    add_params = immapp.AddOnsParams()
    add_params.with_implot = True

    immapp.run(params, add_params)

The thing is, user callbacks need to be set before the glfw backend is initialized (see ImGui_ImplGlfw_InstallCallbacks). This from code not using hello_imgui works fine:

# set our own callbacks before calling
# imgui.backends.glfw_init_for_open_gl(), then imgui's
# glfw backend will chaincall them
glfw.set_char_callback(self.window, self.char_callback)
glfw.set_window_focus_callback(self.window, self.focus_callback)
glfw.set_window_pos_callback(self.window, self.pos_callback)
glfw.set_drop_callback(self.window, self.drop_callback)

# transfer the window address to imgui.backends.glfw_init_for_open_gl
import ctypes
window_address = ctypes.cast(self.window, ctypes.c_void_p).value
imgui.backends.glfw_init_for_open_gl(window_address, True)
imgui.backends.opengl3_init("#version 150")
glfw.swap_interval(globals.settings.vsync_ratio)

Could hello_imgui support this? Perhaps another callback is needed here, for in between glfw window being created and glfw_init_for_open_gl being called?

And a small question: Should i still set fps_idling.enable_idling = False when i already set fps_idling.fps_idle = 0, or are they equivalent? Your haiku demo does both.

pthom commented 1 year ago

This should be fixed by 732a52df05bfb1570a22f2509a34893d3656800f . It fixed the issue on my side. I had to move PostInit call so that it is called a little before ImGui_ImplGlfw_InstallCallbacks

Should i still set fps_idling.enable_idling = False when i already set fps_idling.fps_idle = 0, or are they equivalent? Your haiku demo does both.

You can do either; and do not have to do both: the effect will be the same, except that enable_idling does not override the previous chosen fps)

Please tell if it fixes the issue for you

dcnieho commented 1 year ago

Thanks, that works nicely! And my editor no longer suggests hello_imgui.get_glfw_window(), so thats also fixed with the removed stub :)