class mola::MolaVizImGui

Overview

MOLA visualization — Dear ImGui docking-branch backend.

Implements VizInterface using Dear ImGui + GLFW + OpenGL 3. For the nanogui backend see MolaViz.

#include <MolaVizImGui.h>

class MolaVizImGui:
    public mola::ExecutableBase,
    public mola::VizInterface
{
public:
    // typedefs

    typedef std::string window_name_t;
    typedef std::string subwindow_name_t;
    typedef std::function<void(const mrpt::rtti::CObject::Ptr&, void*subWinHandle, const window_name_t&parentWin, const std::string&subWindowTitle, MolaVizImGui*instance, const mrpt::containers::yaml*extra_parameters)> update_handler_t;
    typedef std::string class_name_t;

    // structs

    struct DataPerDatasetUI;
    struct DecayingCloud;
    struct PerWindowData;
    struct SubWindowState;

    // fields

    static const window_name_t DEFAULT_WINDOW_NAME = "main";
    double console_text_font_size_ = 13.0;
    unsigned int max_console_lines_ = 12;
    bool show_rgbd_as_point_cloud_ = false;
    double assumed_sensor_rate_hz_ = 10.0;
    int target_fps_ = 60;
    std::string imgui_app_name_ = "default";

    // construction

    MolaVizImGui();
    MolaVizImGui(const MolaVizImGui&);
    MolaVizImGui(MolaVizImGui&&);

    // methods

    static bool IsRunning();
    static MolaVizImGui* Instance();

    static void register_gui_handler(
        const class_name_t& name,
        const update_handler_t& handler
        );

    static void register_gui_cleanup(const std::function<void()>& cleanup);
    virtual const std::string& gui_backend() const;
    virtual std::future<void> create_subwindow_from_description(const mola::gui::WindowDescription& desc, const std::string& parentWindow = DEFAULT_WINDOW_NAME);
    virtual std::future<void> enqueue_custom_gui_code(const std::function<void()>& userCode);

    virtual void* get_subwindow_handle(
        const std::string& subWindowTitle,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<std::optional<std::string>> open_file_dialog(
        const std::string& title,
        bool save,
        const std::vector<std::pair<std::string, std::string>>& filters = {},
        const std::string& default_path = "",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<void> set_menu_bar(const mola::gui::MenuBar& bar, const std::string& parentWindow = DEFAULT_WINDOW_NAME);

    virtual std::future<bool> update_3d_object(
        const std::string& objName,
        const std::shared_ptr<mrpt::opengl::CSetOfObjects>& obj,
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> insert_point_cloud_with_decay(
        const std::shared_ptr<mrpt::opengl::CPointCloudColoured>& cloud,
        double decay_time_seconds,
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> clear_all_point_clouds_with_decay(
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> update_viewport_look_at(
        const mrpt::math::TPoint3Df& lookAt,
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> update_viewport_camera_azimuth(
        double azimuth,
        bool absolute_falseForRelative = true,
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> update_viewport_camera_orthographic(
        bool orthographic,
        const std::string& viewportName = "main",
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> execute_custom_code_on_background_scene(
        const std::function<void(mrpt::opengl::Scene&)>& userCode,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> subwindow_update_visualization(
        const mrpt::rtti::CObject::Ptr& obj,
        const std::string& subWindowTitle,
        const mrpt::containers::yaml* extra_parameters = nullptr,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<bool> output_console_message(
        const std::string& msg,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<nanogui::Window*> create_subwindow(
        const std::string& title,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<void> enqueue_custom_nanogui_code(const std::function<void()>& userCode);

    virtual std::future<void> subwindow_grid_layout(
        const std::string& subWindowTitle,
        bool orientationVertical,
        int resolution,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    virtual std::future<void> subwindow_move_resize(
        const std::string& subWindowTitle,
        const mrpt::math::TPoint2D_<int>& location,
        const mrpt::math::TPoint2D_<int>& size,
        const std::string& parentWindow = DEFAULT_WINDOW_NAME
        );

    MolaVizImGui& operator = (const MolaVizImGui&);
    MolaVizImGui& operator = (MolaVizImGui&&);
    virtual void initialize(const Yaml& cfg);
    virtual void spinOnce();
};

Inherited Members

public:
    // typedefs

    typedef std::shared_ptr<VizInterface> Ptr;

    // structs

    struct DiagnosticsOutput;

    // methods

    virtual void initialize(const Yaml& cfg) = 0;
    virtual void spinOnce() = 0;
    ExecutableBase& operator = (const ExecutableBase&);
    ExecutableBase& operator = (ExecutableBase&&);

    virtual std::future<void> create_subwindow_from_description(
        const mola::gui::WindowDescription& desc,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<void> enqueue_custom_gui_code(const std::function<void()>& userCode) = 0;
    virtual const std::string& gui_backend() const = 0;

    virtual std::future<void> set_menu_bar(
        const mola::gui::MenuBar& bar,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual void* get_subwindow_handle(
        const std::string& subWindowTitle,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> update_3d_object(
        const std::string& objName,
        const std::shared_ptr<mrpt::opengl::CSetOfObjects>& obj,
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> insert_point_cloud_with_decay(
        const std::shared_ptr<mrpt::opengl::CPointCloudColoured>& cloud,
        double decay_time_seconds,
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> clear_all_point_clouds_with_decay(
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> update_viewport_look_at(
        const mrpt::math::TPoint3Df& lookAt,
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> update_viewport_camera_azimuth(
        double azimuth,
        bool absolute_falseForRelative = true,
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> update_viewport_camera_orthographic(
        bool orthographic,
        const std::string& viewportName = "main",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> execute_custom_code_on_background_scene(
        const std::function<void(mrpt::opengl::Scene&)>& userCode,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> subwindow_update_visualization(
        const mrpt::rtti::CObject::Ptr& obj,
        const std::string& subWindowTitle,
        const mrpt::containers::yaml* extra_parameters = nullptr,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<bool> output_console_message(
        const std::string& msg,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<std::optional<std::string>> open_file_dialog(
        const std::string& title,
        bool save,
        const std::vector<std::pair<std::string, std::string>>& filters = {},
        const std::string& default_path = "",
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<nanogui::Window*> create_subwindow(
        const std::string& title,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<void> enqueue_custom_nanogui_code(const std::function<void()>& userCode) = 0;

    virtual std::future<void> subwindow_grid_layout(
        const std::string& subWindowTitle,
        bool orientationVertical,
        int resolution,
        const std::string& parentWindow = "main"
        ) = 0;

    virtual std::future<void> subwindow_move_resize(
        const std::string& subWindowTitle,
        const mrpt::math::TPoint2D_<int>& location,
        const mrpt::math::TPoint2D_<int>& size,
        const std::string& parentWindow = "main"
        ) = 0;

    VizInterface& operator = (const VizInterface&);
    VizInterface& operator = (VizInterface&&);

Typedefs

typedef std::function<void(const mrpt::rtti::CObject::Ptr&, void*subWinHandle, const window_name_t&parentWin, const std::string&subWindowTitle, MolaVizImGui*instance, const mrpt::containers::yaml*extra_parameters)> update_handler_t

Sensor-observation rendering handler signature. subWin is nullptr for the ImGui backend — use subWindowTitle to key ImGui state instead.

Fields

std::string imgui_app_name_ = "default"

Identifier used to persist ImGui window layout / docking state across runs: each distinct value maps to its own imgui_<app_name>.ini file under $XDG_CONFIG_HOME/mola/ (or $HOME/.config/mola/). Set a different name per launch config (e.g. “kitti_replay”, “live_lio”) to keep layouts separate. Empty string disables persistence.

Methods

static void register_gui_cleanup(const std::function<void()>& cleanup)

Register a callback that will be invoked on the GUI thread during shutdown, with the GL context still current, before any GLFW window is destroyed. Handlers use this to release GL resources held in function-local static state (FBOs, textures, VAOs in CImGuiSceneView, …) without risking calls on a dead context.

virtual const std::string& gui_backend() const

Returns a short identifier string for the active GUI backend.

Clients may use this to conditionally tune their GUIs - for example to choose between an Entypo icon (nanogui) and a FontAwesome codepoint (ImGui), or to skip features not yet supported on a given backend.

Canonical values are provided as static constants below: VizInterface::BACKEND_NANOGUI → “nanogui” VizInterface::BACKEND_IMGUI → “imgui”

Comparison example:

if (visualizer_->gui_backend() == VizInterface::BACKEND_IMGUI) { ... }

The method is pure virtual so each concrete backend is forced to declare its identity explicitly. It is noexcept and const so it is safe to call from any context, including hot loops.

virtual std::future<void> create_subwindow_from_description(
    const mola::gui::WindowDescription& desc,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Creates a sub-window described by a GuiWidgetDescription.

The description carries the window title, initial position/size hints, tab structure, and all widget definitions including their initial values and on_change callbacks.

The returned future resolves once the window has been created in the GUI thread and all widgets are live. Callers that need to know when construction is complete should call .get() on the future.

Position and size in the description are treated as first-use hints :

  • nanogui backend : applied unconditionally via setPosition/setFixedWidth.

  • ImGui backend : passed as ImGuiCond_FirstUseEver, so the dock manager and imgui.ini take over from the second run.

Label text is updated at any time and from any thread by calling LiveString::set() on the LiveString instances embedded in the description. The backend polls them on each frame / spinOnce tick.

Parameters:

desc

Full window and widget description.

parentWindow

Name of the parent host window (default: “main”).

Returns:

future<void> that resolves when the window is live.

See also:

mola::gui::WindowDescription, mola::gui::LiveString

virtual std::future<void> enqueue_custom_gui_code(const std::function<void()>& userCode)

Enqueues arbitrary code to run on the GUI thread at the next available opportunity.

Use this for any GUI-thread work that is not covered by the widget description API: e.g. updating widget enable/disable state, changing slider ranges at runtime, or interacting with toolkit-specific objects via a cast of the opaque handle returned by get_subwindow_handle().

The callable is executed in the GUI thread; do not call blocking operations inside it.

This replaces the deprecated enqueue_custom_nanogui_code().

virtual void* get_subwindow_handle(
    const std::string& subWindowTitle,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Returns an opaque handle to a previously created sub-window.

The handle type depends on the backend:

Returns nullptr if the window does not exist yet or the backend does not support retained window objects.

This is an intentional “escape hatch” for toolkit-specific code that cannot be expressed through the description API. Prefer enqueue_custom_gui_code() over casting this pointer wherever possible, as that keeps the calling module’s cpp file free of GUI toolkit headers.

virtual std::future<std::optional<std::string>> open_file_dialog(
    const std::string& title,
    bool save,
    const std::vector<std::pair<std::string, std::string>>& filters = {},
    const std::string& default_path = "",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Opens a modal file-picker dialog on the GUI thread.

The call is non-blocking: it enqueues the dialog to open on the GUI thread and returns a future that resolves when the user dismisses it.

Parameters:

title

Dialog window title, e.g. “Open point cloud”.

save

true → “Save as” dialog (prompts before overwrite). false → “Open” dialog (validates file exists).

filters

List of {description, comma-separated-extensions} pairs. Example: {{“LAS files”,”las,laz”},{“All files”,”*”}} Pass an empty vector to show all files.

default_path

Initial directory or full path suggestion. Empty string means the backend’s default (usually the current working directory).

parentWindow

Host window name.

Returns:

future resolving to the chosen absolute path, or std::nullopt if the user cancelled.

virtual std::future<void> set_menu_bar(
    const mola::gui::MenuBar& bar,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Installs or replaces the menu bar of a parent window.

Menu bars are a first-class feature of the Dear ImGui docking branch (ImGui::BeginMainMenuBar / BeginMenuBar). The nanogui backend has no native equivalent and provides a no-op stub that resolves the future immediately without rendering anything. Callers should guard with gui_backend() if the menus are essential to their workflow:

if (visualizer_->gui_backend() == VizInterface::BACKEND_IMGUI)
    visualizer_->set_menu_bar(bar);

Parameters:

bar

Full menu bar description.

parentWindow

Host window whose menu bar is replaced.

Returns:

future<void> resolving when the menu bar is live.

virtual std::future<bool> update_3d_object(
    const std::string& objName,
    const std::shared_ptr<mrpt::opengl::CSetOfObjects>& obj,
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Updates or inserts a 3D object in the background scene.

The update is performed in the GUI thread. If the named object already exists, its contents are replaced by copying the shared pointers inside obj.

Parameters:

objName

Name used to identify the object (upsert key).

obj

Object to display.

viewportName

Viewport inside the parent window.

parentWindow

Host window name.

Returns:

future<bool>; resolves to true when executed.

virtual std::future<bool> insert_point_cloud_with_decay(
    const std::shared_ptr<mrpt::opengl::CPointCloudColoured>& cloud,
    double decay_time_seconds,
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Inserts a temporary point cloud visible for decay_time_seconds.

Parameters:

cloud

Cloud to display.

decay_time_seconds

Lifetime in seconds before the cloud fades out.

viewportName

Target viewport.

parentWindow

Host window name.

Returns:

future<bool> resolving to true when executed.

virtual std::future<bool> clear_all_point_clouds_with_decay(
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Removes all clouds previously inserted with insert_point_cloud_with_decay().

virtual std::future<bool> update_viewport_look_at(
    const mrpt::math::TPoint3Df& lookAt,
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Moves the viewport camera look-at point.

virtual std::future<bool> update_viewport_camera_azimuth(
    double azimuth,
    bool absolute_falseForRelative = true,
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Rotates the viewport camera around the vertical axis.

Parameters:

azimuth

Angle in radians.

absolute_falseForRelative

true → set absolute azimuth; false → add increment to current value.

virtual std::future<bool> update_viewport_camera_orthographic(
    bool orthographic,
    const std::string& viewportName = "main",
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Switches the viewport camera between perspective and orthographic.

virtual std::future<bool> execute_custom_code_on_background_scene(
    const std::function<void(mrpt::opengl::Scene&)>& userCode,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Executes arbitrary user code on the mrpt::opengl::Scene of the background viewport.

Use this to modify viewport properties, add sub-viewports, change background colour, etc. The callable runs in the GUI thread.

This method operates on the mrpt OpenGL scene, not on GUI toolkit widgets, so it is backend-agnostic: both nanogui and ImGui backends embed an mrpt scene in their OpenGL canvas.

virtual std::future<bool> subwindow_update_visualization(
    const mrpt::rtti::CObject::Ptr& obj,
    const std::string& subWindowTitle,
    const mrpt::containers::yaml* extra_parameters = nullptr,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Updates a sub-window’s content from an MRPT object.

The correct handler is selected based on the runtime type of obj. Custom handlers can be registered via MolaViz::register_gui_handler().

Returns:

future<bool> resolving to false if no handler exists for the object’s type.

virtual std::future<bool> output_console_message(
    const std::string& msg,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Appends a line of text to the on-screen console overlay.

virtual std::future<nanogui::Window*> create_subwindow(
    const std::string& title,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Deprecated Use create_subwindow_from_description() instead.

Returns a nanogui::Window* through a future. On non-nanogui backends this returns a future containing nullptr; callers must guard against this. The returned pointer must not be deleted by the caller.

virtual std::future<void> enqueue_custom_nanogui_code(const std::function<void()>& userCode)

Deprecated Use enqueue_custom_gui_code() instead.

Retained for source compatibility; both names dispatch to the same internal queue.

virtual std::future<void> subwindow_grid_layout(
    const std::string& subWindowTitle,
    bool orientationVertical,
    int resolution,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Deprecated Encode layout in WindowDescription::tabs instead.

On ImGui backends this is a no-op (ImGui manages layout automatically).

virtual std::future<void> subwindow_move_resize(
    const std::string& subWindowTitle,
    const mrpt::math::TPoint2D_<int>& location,
    const mrpt::math::TPoint2D_<int>& size,
    const std::string& parentWindow = DEFAULT_WINDOW_NAME
    )

Deprecated Encode position and size in WindowDescription instead.

On ImGui backends position/size are first-use hints only; the dock manager overrides them freely.

virtual void initialize(const Yaml& cfg)

This must be implemented to read all the required parameters

This should be reimplemented to read all the required parameters

virtual void spinOnce()

Runs any required action on a timely manner