| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- # Part of ImGui Bundle - MIT License - Copyright (c) 2022-2026 Pascal Thomet - https://github.com/pthom/imgui_bundle
- """Async support for HelloImGui - enables non-blocking GUI execution."""
- import asyncio
- from typing import Any, Optional, Callable, Tuple, overload
- from imgui_bundle.hello_imgui import RunnerParams, SimpleRunnerParams
- @overload
- async def run_async(
- runner_params: RunnerParams,
- ) -> None:
- """Run an application asynchronously using RunnerParams.
- This function will run until the application exits (user closes window or app_shall_exit is set).
- Use this when you need full control over the async lifecycle.
- Example:
- async def my_app():
- runner = hello_imgui.RunnerParams()
- runner.callbacks.show_gui = my_gui_function
- await hello_imgui.run_async(runner)
- print("GUI closed")
- asyncio.run(my_app())
- """
- ...
- @overload
- async def run_async(
- simple_params: SimpleRunnerParams,
- ) -> None:
- """Run an application asynchronously using SimpleRunnerParams."""
- ...
- @overload
- async def run_async(
- gui_function: Callable[[], None],
- window_title: str = "",
- window_size_auto: bool = False,
- window_restore_previous_geometry: bool = False,
- window_size: Optional[Tuple[int, int]] = None,
- fps_idle: float = 10.0,
- top_most: bool = False,
- ) -> None:
- """Run an application asynchronously using a simple GUI function and parameters."""
- ...
- async def run_async(*args: Any, **kwargs: Any) -> None:
- """Run a HelloImGui application asynchronously in a non-blocking way.
- This function provides async/await support for HelloImGui applications.
- It will run until the application exits (user closes window or app_shall_exit is set).
- Three signatures are supported:
- 1. run_async(runner_params: RunnerParams)
- 2. run_async(simple_params: SimpleRunnerParams)
- 3. run_async(gui_function, window_title="", window_size_auto=False, ...)
- For Jupyter notebook usage, see hello_imgui.nb.start() for a more convenient API.
- """
- # Import here to avoid issues at module load time
- from imgui_bundle import hello_imgui
- manual_render = hello_imgui.manual_render
- # Determine which setup method to use based on arguments
- if len(args) >= 1:
- first_arg = args[0]
- # Case 1: RunnerParams
- if isinstance(first_arg, RunnerParams):
- runner_params = first_arg
- manual_render.setup_from_runner_params(runner_params)
- # Case 2: SimpleRunnerParams
- elif isinstance(first_arg, SimpleRunnerParams):
- simple_params = first_arg
- manual_render.setup_from_simple_runner_params(simple_params)
- # Case 3: GUI function with keyword arguments
- elif callable(first_arg):
- gui_function = first_arg
- # Extract parameters, using defaults from hello_imgui.run signature
- window_title = kwargs.get("window_title", "")
- window_size_auto = kwargs.get("window_size_auto", False)
- window_restore_previous_geometry = kwargs.get("window_restore_previous_geometry", False)
- window_size = kwargs.get("window_size", None)
- fps_idle = kwargs.get("fps_idle", 10.0)
- top_most = kwargs.get("top_most", False)
- manual_render.setup_from_gui_function(
- gui_function,
- window_title=window_title,
- window_size_auto=window_size_auto,
- window_restore_previous_geometry=window_restore_previous_geometry,
- window_size=window_size,
- fps_idle=fps_idle,
- top_most=top_most,
- )
- else:
- raise TypeError(f"First argument must be RunnerParams, SimpleRunnerParams, or a callable GUI function, got {type(first_arg)}")
- else:
- raise TypeError("run_async() requires at least one argument")
- # Configure FPS settings for optimal async performance
- # EarlyReturn mode ensures C++ code never blocks: it returns immediately
- # and tells Python how long to wait (see _priv_idle_frame_wait_duration_for_python_async_io)
- params = hello_imgui.get_runner_params()
- params.fps_idling.fps_idling_mode = hello_imgui.FpsIdlingMode.early_return
- params.fps_idling.vsync_to_monitor = False # vsync is implemented via sleep in the backend
- if params.fps_idling.fps_max <= 0.0:
- params.fps_idling.fps_max = 60.0 # default cap to avoid 1000+ FPS spins
- # Async render loop
- try:
- while not hello_imgui.get_runner_params().app_shall_exit:
- manual_render.render()
- wait_time = hello_imgui._priv_idle_frame_wait_duration_for_python_async_io() # type: ignore
- if wait_time > 0.0:
- await asyncio.sleep(wait_time)
- else:
- await asyncio.sleep(0)
- finally:
- # Ensure cleanup happens even if an exception occurs
- manual_render.tear_down()
|