GUI Viewport¶
This example shows a Datoviz render viewport embedded inside a GUI window.
Preview¶

Run And Adapt¶
Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.
| Route | Availability | Command or action |
|---|---|---|
| C | Canonical native source | just example-c features/gui_viewport (build and run), or rerun ./build/examples/c/features/gui_viewport |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.gui_viewport |
| Browser | Native only | dockable GUI viewports require native ImGui and an offscreen native source view |
Use this example as capability or integration evidence, not as a minimal copy-paste template. Start from the nearest supported, copy-safe example and add this feature after verifying the linked API reference.
What To Look For¶
The application hosts a GUI window while a separate Datoviz figure renders a small point scene at a fixed source size. The viewport presents that live render target inside the GUI instead of as the whole native window. Compare the embedded plot area with the surrounding controls; this layout is useful for tools where plots, parameter widgets, and diagnostics need to share the same application surface.
Source¶
#!/usr/bin/env python3
"""Native GUI window hosting an embedded Datoviz render viewport."""
from __future__ import annotations
import ctypes
import numpy as np
import datoviz as dvz
from examples.python.gallery import common as ex
HOST_WIDTH = ex.WIDTH
HOST_HEIGHT = ex.HEIGHT
SOURCE_WIDTH = 640
SOURCE_HEIGHT = 480
POINT_COUNT = 5
class GuiViewportState:
def __init__(self, point) -> None:
self.viewport = None
self.point = point
self.diameter_px = ctypes.c_float(34.0)
self.show_points = ctypes.c_bool(True)
self.show_demo = ctypes.c_bool(False)
def _positions() -> np.ndarray:
return np.array(
[
[-0.68, -0.45, 0.0],
[-0.28, +0.28, 0.0],
[+0.00, -0.05, 0.0],
[+0.34, +0.48, 0.0],
[+0.72, -0.25, 0.0],
],
dtype=np.float32,
)
def _colors() -> np.ndarray:
return ex.color_array(ex.CYAN, ex.GREEN, ex.YELLOW, ex.TEXT, ex.BLUE)
def _upload(state: GuiViewportState) -> None:
diameter = state.diameter_px.value if state.show_points.value else 0.0
diameters = np.full(POINT_COUNT, diameter, dtype=np.float32)
if dvz.dvz_visual_set_data(state.point, "diameter_px", diameters) != 0:
raise RuntimeError("dvz_visual_set_data(diameter_px) failed")
def _build_scene():
scene = dvz.dvz_scene()
if not scene:
raise RuntimeError("dvz_scene() failed")
source_figure = dvz.dvz_figure(scene, SOURCE_WIDTH, SOURCE_HEIGHT, 0)
host_figure = dvz.dvz_figure(scene, HOST_WIDTH, HOST_HEIGHT, 0)
if not source_figure or not host_figure:
raise RuntimeError("dvz_figure() failed")
source_panel = dvz.dvz_panel_full(source_figure)
host_panel = dvz.dvz_panel_full(host_figure)
if not source_panel or not host_panel:
raise RuntimeError("dvz_panel_full() failed")
dvz.dvz_panel_set_background_color(source_panel, ex.BG)
dvz.dvz_panel_set_background_color(host_panel, dvz.DvzColor(11, 13, 16, 255))
point = dvz.dvz_point(scene, 0)
if not point:
raise RuntimeError("dvz_point() failed")
state = GuiViewportState(point)
_upload(state)
if dvz.dvz_visual_set_data_many(
point,
{
"position": _positions(),
"color": _colors(),
},
) != 0:
raise RuntimeError("dvz_visual_set_data_many(point) failed")
ex.set_filled_point_style(point)
ex.add_visual(source_panel, point)
return scene, source_figure, host_figure, source_panel, state
def _gui_callback_factory(state: GuiViewportState):
def gui_callback(gui, _view, _user_data) -> None:
if state.viewport:
dvz.dvz_gui_viewport_window(state.viewport, b"Datoviz viewport", None, 0)
changed = False
if dvz.dvz_gui_begin(gui, b"Viewport controls", None, 0):
changed |= dvz.dvz_gui_slider_float(
gui, b"Diameter", ctypes.byref(state.diameter_px), 4.0, 80.0
)
changed |= dvz.dvz_gui_checkbox(gui, b"Show points", ctypes.byref(state.show_points))
dvz.dvz_gui_checkbox(gui, b"ImGui demo", ctypes.byref(state.show_demo))
dvz.dvz_gui_end(gui)
if state.show_demo.value:
dvz.dvz_gui_demo(gui, ctypes.byref(state.show_demo))
if changed:
_upload(state)
return gui_callback
def _configure_gui_viewport(view, scene, source_figure, source_panel, state: GuiViewportState) -> None:
gui = dvz.dvz_view_gui(view, None)
if not gui:
raise RuntimeError("dvz_view_gui() failed")
config = dvz.dvz_gui_viewport_config()
config.viewport_flags = dvz.DVZ_GUI_VIEWPORT_FLAGS_FORWARD_INPUT
viewport = dvz.dvz_gui_viewport(gui, source_figure, ctypes.byref(config))
if not viewport:
raise RuntimeError("dvz_gui_viewport() failed")
state.viewport = viewport
panzoom = dvz.dvz_panzoom(scene, None)
if not panzoom:
raise RuntimeError("dvz_panzoom() failed")
if dvz.dvz_panel_bind_controller(source_panel, panzoom, dvz.DVZ_DIM_MASK_XY) != 0:
raise RuntimeError("dvz_panel_bind_controller() failed")
router = dvz.dvz_gui_viewport_input(viewport)
if not router:
raise RuntimeError("dvz_gui_viewport_input() failed")
if dvz.dvz_panel_connect_input(source_panel, router) != 0:
raise RuntimeError("dvz_panel_connect_input() failed")
if dvz.dvz_view_set_gui_callback(view, _gui_callback_factory(state), None) != 0:
raise RuntimeError("dvz_view_set_gui_callback() failed")
def main() -> None:
scene, source_figure, host_figure, source_panel, state = _build_scene()
app = dvz.dvz_app(scene)
if not app:
raise RuntimeError("dvz_app() failed")
try:
view = dvz.dvz_view_window(app, host_figure, HOST_WIDTH, HOST_HEIGHT, b"GUI Viewport")
if not view:
raise RuntimeError("dvz_view_window() failed")
_configure_gui_viewport(view, scene, source_figure, source_panel, state)
ex.run_app(app, view)
finally:
dvz.dvz_app_destroy(app)
dvz.dvz_scene_destroy(scene)
if __name__ == "__main__":
main()
/*
* Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for details.
* SPDX-License-Identifier: MIT
*/
/* gui_viewport - This example shows a Datoviz render viewport embedded inside a GUI window.
*
* Scenario: features_gui_viewport
* Style: features, native GUI/app
*
* Build: just example-c features/gui_viewport
* Run: ./build/examples/c/features/gui_viewport
*
* What to look for: the application hosts a GUI window while a separate Datoviz figure renders a
* small point scene at a fixed source size. The viewport presents that live render target inside
* the GUI instead of as the whole native window. Compare the embedded plot area with the surrounding
* controls; this layout is useful for tools where plots, parameter widgets, and diagnostics need to
* share the same application surface.
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "datoviz/app.h"
#include "datoviz/gui.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define HOST_WIDTH EXAMPLE_WINDOW_WIDTH
#define HOST_HEIGHT EXAMPLE_WINDOW_HEIGHT
#define SOURCE_WIDTH 640u
#define SOURCE_HEIGHT 480u
#define POINT_COUNT 5u
/*************************************************************************************************/
/* Structs */
/*************************************************************************************************/
typedef struct GuiViewportState
{
DvzGuiViewport* viewport;
DvzVisual* point;
float diameter_px;
bool show_points;
bool show_demo;
} GuiViewportState;
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Upload the point diameters controlled by the host GUI.
*
* @param state GUI viewport state
* @return true on success
*/
static bool _gui_viewport_upload(GuiViewportState* state)
{
if (state == NULL || state->point == NULL)
return false;
const float diameter_px = state->show_points ? state->diameter_px : 0.0f;
float diameters[POINT_COUNT] = {diameter_px, diameter_px, diameter_px, diameter_px, diameter_px};
return dvz_visual_set_data(state->point, "diameter_px", diameters, POINT_COUNT) == 0;
}
/**
* Build the dockable GUI viewport and its controls.
*
* @param gui GUI overlay
* @param view host GLFW view
* @param user_data GUI viewport state
*/
static void _gui_viewport_callback(DvzGui* gui, DvzView* view, void* user_data)
{
(void)view;
GuiViewportState* state = (GuiViewportState*)user_data;
if (state == NULL || state->viewport == NULL)
return;
(void)dvz_gui_viewport_window(state->viewport, "Datoviz viewport", NULL, 0);
bool changed = false;
if (dvz_gui_begin(gui, "Viewport controls", NULL, 0))
{
changed |= dvz_gui_slider_float(gui, "Diameter", &state->diameter_px, 4.0f, 80.0f);
changed |= dvz_gui_checkbox(gui, "Show points", &state->show_points);
(void)dvz_gui_checkbox(gui, "ImGui demo", &state->show_demo);
}
dvz_gui_end(gui);
if (state->show_demo)
dvz_gui_demo(gui, &state->show_demo);
if (changed && !_gui_viewport_upload(state))
dvz_fprintf(stderr, "gui_viewport: failed to upload point sizes\n");
}
/*************************************************************************************************/
/* Main */
/*************************************************************************************************/
int main(int argc, char** argv)
{
int ret = 1;
DvzScene* scene = NULL;
DvzApp* app = NULL;
DvzView* host_view = NULL;
DvzPanel* source_panel = NULL;
DvzGuiViewport* viewport = NULL;
bool host_alive = false;
scene = dvz_scene();
EXAMPLE_CHECK(scene != NULL, "dvz_scene() failed");
DvzFigure* source_figure = dvz_figure(scene, SOURCE_WIDTH, SOURCE_HEIGHT, 0);
DvzFigure* host_figure = dvz_figure(scene, HOST_WIDTH, HOST_HEIGHT, 0);
EXAMPLE_CHECK(source_figure != NULL && host_figure != NULL, "dvz_figure() failed");
source_panel = dvz_panel_full(source_figure);
DvzPanel* host_panel = dvz_panel_full(host_figure);
EXAMPLE_CHECK(source_panel != NULL && host_panel != NULL, "dvz_panel_full() failed");
example_graphite_cyan_set_panel_background(source_panel);
dvz_panel_set_background_color(host_panel, dvz_color_from_unit(0.045f, 0.050f, 0.064f, 1.0f));
DvzVisual* point = dvz_point(scene, 0);
EXAMPLE_CHECK(point != NULL, "dvz_point() failed");
GuiViewportState state = {
.point = point,
.diameter_px = 34.0f,
.show_points = true,
};
vec3 positions[POINT_COUNT] = {
{-0.68f, -0.45f, 0.0f}, {-0.28f, +0.28f, 0.0f}, {+0.00f, -0.05f, 0.0f},
{+0.34f, +0.48f, 0.0f}, {+0.72f, -0.25f, 0.0f},
};
DvzColor colors[POINT_COUNT] = {
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_PRIMARY),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_ACCENT_SECONDARY),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_TEXT),
example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_MINOR_TICK),
};
EXAMPLE_CHECK(_gui_viewport_upload(&state), "failed to upload point sizes");
DvzVisualDataUpdate updates[] = {
{.attr_name = "position", .data = positions, .item_count = POINT_COUNT},
{.attr_name = "color", .data = colors, .item_count = POINT_COUNT},
};
EXAMPLE_CHECK(dvz_visual_set_data_many(point, updates, 2) == 0, "failed to upload point data");
EXAMPLE_CHECK(
dvz_panel_add_visual(source_panel, point, NULL) == 0, "dvz_panel_add_visual() failed");
app = dvz_app(scene);
EXAMPLE_CHECK(app != NULL, "dvz_app() failed (no GPU or display?)");
host_view = dvz_view_window(app, host_figure, HOST_WIDTH, HOST_HEIGHT, "gui_viewport");
EXAMPLE_CHECK(host_view != NULL, "dvz_view_window() failed (GLFW unavailable?)");
DvzGui* gui = dvz_view_gui(host_view, NULL);
EXAMPLE_CHECK(gui != NULL, "dvz_view_gui() failed");
DvzGuiViewportConfig viewport_config = dvz_gui_viewport_config();
viewport_config.viewport_flags = DVZ_GUI_VIEWPORT_FLAGS_FORWARD_INPUT;
viewport = dvz_gui_viewport(gui, source_figure, &viewport_config);
EXAMPLE_CHECK(viewport != NULL, "dvz_gui_viewport() failed");
state.viewport = viewport;
DvzController* panzoom = dvz_panzoom(scene, NULL);
EXAMPLE_CHECK(panzoom != NULL, "dvz_panzoom() failed");
EXAMPLE_CHECK(
dvz_panel_bind_controller(source_panel, panzoom, DVZ_DIM_MASK_XY) == 0,
"dvz_panel_bind_controller() failed");
EXAMPLE_CHECK(
dvz_panel_connect_input(source_panel, dvz_gui_viewport_input(viewport)) == 0,
"dvz_panel_connect_input() failed");
dvz_view_set_gui_callback(host_view, _gui_viewport_callback, &state);
if (example_png_capture_requested(argc, argv))
{
DvzAppCaptureConfig capture = {0};
EXAMPLE_CHECK(
example_png_capture_config("feature_gui_viewport", &capture),
"failed to configure PNG capture");
EXAMPLE_CHECK(
example_run_with_capture(
app, host_view, example_frame_count_any_or_default(argc, argv, 4), &capture),
"PNG capture failed");
}
else
{
dvz_app_run(app, example_frame_count(argc, argv));
}
ret = 0;
cleanup:
host_alive = host_view != NULL && dvz_view_canvas(host_view) != NULL;
if (host_alive)
(void)dvz_view_set_gui_callback(host_view, NULL, NULL);
if (source_panel != NULL && viewport != NULL && host_alive)
(void)dvz_panel_connect_input(source_panel, NULL);
if (viewport != NULL && host_alive)
dvz_gui_viewport_destroy(viewport);
if (app != NULL)
dvz_app_destroy(app);
if (scene != NULL)
dvz_scene_destroy(scene);
return ret;
}
Example details
- ID:
features_gui_viewport - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/gui_viewport.c - Approved adaptation starter:
no - Python source:
examples/python/gallery/features/gui_viewport.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Native only
- Browser note: dockable GUI viewports require native ImGui and an offscreen native source view
- Browser capability tags:
gui,native-view - Validation:
smoke+interaction+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |