Emit GUI signal to “click” button programmatically

In Omni.kit.window.movie_maker

I would like to be able to set the values that the GUI function needs and then press the button to make a sequence of images based on an Omni verse scene also loaded/created programmatically

Using the GUI is simple enough but if I wish to create millions of outputs this is not suitable

In pyside I can call button.click().emit or similar and that event will be processed by the appropriate event listeners

But I cannot comprehend how to emit signals in the carbonite UI event loop

Sam

@eoinm

Sorry to be dragging you all over the forum, but this might be useful to other users.

No problem.
If you are able to get a reference to the widget that you want to execute the callback on, you can do e.g:
widget.call_mouse_clicked_fn(0, 0, 0, 0)
In general, for every callback there is (in python) a “call_”, “set_”, “has_” method that gets auto-generated for it.
Eoin

Dude!

That is perfect.

I can puppet the GUI with this adequately

I might even do a tutorial on the subject for the community

Sam

I might even do a tutorial on the subject for the community

That would be so great!

This is not going so great
While this code does produce output

capture.py

from pathlib import Path
import omni
import asyncio
import omni.kit.file
from pxr import Usd
import logging


def setup_logging(level=logging.INFO):
    logging.basicConfig(level=level)

    urllib3_logger = logging.getLogger("urllib3")
    urllib3_logger.setLevel(logging.INFO)


setup_logging()


def get_stage_from_path(path: Path):
    return Usd.Stage.Open(path.as_posix())


def get_camera_strings_from_stage(stage: Usd.Stage):
    camera_strings = []
    for prim in stage.Traverse():
        if prim.GetTypeName() == "Camera":
            camera_strings.append(str(prim.GetPath()))
    return camera_strings


def get_cameras_from_usd(path: Path):
    stage = get_stage_from_path(path)
    camera_strings = get_camera_strings_from_stage(stage)
    return camera_strings


async def capture_usd_scene(
    usd_file: str = "./data/raw/shipsShaded.usd",
    output_file_pattern: str = "data/omniverse/capture/frame.####.png",
    camera: str = "/Camera/Camera_001",
    start_frame: int = 1,
    end_frame: int = 50,
    resolution_width: int = 1920,
    resolution_height: int = 1080,
    intermediate_usd: str = "./data/raw/temp.usd",
):
    """
    Create Frames from USD file through camera for time range
    """
    input_usd = (Path(__file__).parent.parent / Path(usd_file)).as_posix()
    intermediate_usd_file = (
        Path(__file__).parent.parent / Path(intermediate_usd)
    ).as_posix()
    input_stage = get_stage_from_path(Path(input_usd))
    for cur_camera in get_cameras_from_usd(Path(input_usd)):
        if cur_camera != camera:
            if input_stage.RemovePrim(cur_camera):
                logging.info(f"Removed spare camera {cur_camera}")
            else:
                pass
    input_stage.Export(intermediate_usd_file)
    omni.kit.file.open_stage(intermediate_usd_file)
    if not Path(intermediate_usd_file).is_file():
        logging.error(
            f"ERROR {Path(usd_file).as_posix()} is not a file, should be a USD file"
        )
        return
    window = omni.kit.window.movie_maker.window.MovieMakerWindow()
    output_settings = window._output_settings_widget
    window._capture_settings_widget._ui_res_width_input.value = resolution_width
    window._capture_settings_widget._ui_res_height_input.value = resolution_height
    window._capture_settings_widget._ui_start_frame_input.value = start_frame
    window._capture_settings_widget._ui_end_frame_input.value = end_frame
    window = omni.kit.window.movie_maker.window.MovieMakerWindow()
    output_settings = window._output_settings_widget
    output_settings._ui_kit_default_capture_name.model.set_value(
        Path(output_file_pattern).name.split(".")[0]
    )
    output_settings._ui_kit_path.model.set_value(
        (Path(output_file_pattern).parent / Path(camera).as_posix()[1:]).as_posix()
    )
    output_settings._on_capture_sequence_clicked()
    return True


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    capture_window = loop.run_until_complete(capture_usd_scene())

When executed as

 kaolin.sh \
         --exec \
         "./path/capture.py" \
         --no-window \
         --/app/quitAfter=100

and

the USD file has a location of

./data/raw/shipsShaded.usd

and has a camera called

/Camera/Camera_001

the you get output such as

./data/omniverse/capture/Camera/Camera_001/frame_1th_frames/frame.0002.png

Which is possible to rename to the intended file path in a chase script

But the only reason why the script works is because there is no command to close the application

it is relying on --/app/quitAfter=100 which seems bad.

How can I get a signal from the progress window and wait on this window to be completed in a non blocking asyncio way?

Then issue the quit command?

For bonus points how to I get args to come through from the command line?

Hi Sam,
not able to answer all of your problems right now as I’m not in front of a machine, but,instead of --/app/quitAfter=100 you can use:

omni.kit.app.get_app().post_quit(0)

which is async, and should wait for your tasks to finish.

To parse command line args, I think you just need to put them inside the quotes of your script filename, so:

 kaolin.sh \
         --exec \
         "./path/capture.py arg1 arg2 argN" \
         --no-window \
         --/app/quitAfter=100

You can then use argparse to parse those args just like in a normal python script