Added Documentation

This commit is contained in:
Robin Quint 2022-03-04 15:49:43 +01:00
parent 3da8f2cf33
commit 768034a681
3 changed files with 120 additions and 7 deletions

View File

@ -60,6 +60,8 @@ pub struct Context {
// imgui a mutable pointer to it.
clipboard_ctx: Box<UnsafeCell<ClipboardContext>>,
// we need to store an owning reference to our PlatformViewportBackend and PlatformRendererBackend,
// so that it is ensured that PlatformIo::backend_platform_user_data and PlatformIo::backend_renderer_user_data remain valid
#[cfg(feature = "docking")]
platform_viewport_ctx: Box<UnsafeCell<crate::PlatformViewportContext>>,
#[cfg(feature = "docking")]
@ -592,39 +594,77 @@ impl Context {
#[cfg(feature = "docking")]
impl Context {
/// Returns an immutable reference to the Context's [`PlatformIo`](crate::PlatformIo) object.
pub fn platform_io(&self) -> &crate::PlatformIo {
unsafe {
// safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO
// and &self ensures we have shared ownership of PlatformIo.
&*(sys::igGetPlatformIO() as *const crate::PlatformIo)
}
}
/// Returns a mutable reference to the Context's [`PlatformIo`](crate::PlatformIo) object.
pub fn platform_io_mut(&mut self) -> &mut crate::PlatformIo {
unsafe {
// safe because PlatformIo is a transparent wrapper around sys::ImGuiPlatformIO
// and &mut self ensures exclusive ownership of PlatformIo.
&mut *(sys::igGetPlatformIO() as *mut crate::PlatformIo)
}
}
/// Returns an immutable reference to the main [`Viewport`](crate::Viewport)
pub fn main_viewport(&self) -> &crate::Viewport {
unsafe { &*(sys::igGetMainViewport() as *mut crate::Viewport) }
unsafe {
// safe because Viewport is a transparent wrapper around sys::ImGuiViewport
// and &self ensures we have shared ownership.
&*(sys::igGetMainViewport() as *mut crate::Viewport)
}
}
/// Returns a mutable reference to the main [`Viewport`](crate::Viewport)
pub fn main_viewport_mut(&mut self) -> &mut crate::Viewport {
unsafe { &mut *(sys::igGetMainViewport() as *mut crate::Viewport) }
unsafe {
// safe because Viewport is a transparent wrapper around sys::ImGuiViewport
// and &mut self ensures we have exclusive ownership.
&mut *(sys::igGetMainViewport() as *mut crate::Viewport)
}
}
/// Tries to find and return a Viewport identified by `id`.
///
/// # Returns
/// A [`Viewport`](crate::Viewport) with the given `id`
/// or `None` if no [`Viewport`](crate::Viewport) exists.
pub fn viewport_by_id(&self, id: crate::Id) -> Option<&crate::Viewport> {
unsafe { (sys::igFindViewportByID(id.0) as *const crate::Viewport).as_ref() }
unsafe {
// safe because Viewport is a transparent wrapper around sys::ImGuiViewport
// and &self ensures shared ownership.
(sys::igFindViewportByID(id.0) as *const crate::Viewport).as_ref()
}
}
/// Tries to find and return a Viewport identified by `id`.
///
/// # Returns
/// A [`Viewport`](crate::Viewport) with the given `id`
/// or `None` if no [`Viewport`](crate::Viewport) exists.
pub fn viewport_by_id_mut(&mut self, id: crate::Id) -> Option<&mut crate::Viewport> {
unsafe { (sys::igFindViewportByID(id.0) as *mut crate::Viewport).as_mut() }
unsafe {
// safe because Viewport is a transparent wrapper around sys::ImGuiViewport
// and &mut self ensures exclusive ownership.
(sys::igFindViewportByID(id.0) as *mut crate::Viewport).as_mut()
}
}
/// Returns an iterator containing every [`Viewport`](crate::Viewport) that currently exists.
pub fn viewports(&self) -> impl Iterator<Item = &crate::Viewport> {
let slice = self.platform_io().viewports.as_slice();
// safe because &self ensures shared ownership
unsafe { slice.iter().map(|ptr| &**ptr) }
}
/// Returns an iterator containing every [`Viewport`](crate::Viewport) that currently exists.
pub fn viewports_mut(&mut self) -> impl Iterator<Item = &mut crate::Viewport> {
let slice = self.platform_io_mut().viewports.as_slice();
// safe because &self ensures exclusive ownership
unsafe { slice.iter().map(|ptr| &mut **ptr) }
}
/// Installs a [`PlatformViewportBackend`](crate::PlatformViewportBackend) that is used to
/// create platform windows on demand if a window is dragged outside of the main viewport.
pub fn set_platform_backend<T: crate::PlatformViewportBackend>(&mut self, backend: T) {
let ctx = Box::new(UnsafeCell::new(crate::PlatformViewportContext {
backend: Box::new(backend),
@ -638,7 +678,7 @@ impl Context {
pio.platform_destroy_window = Some(crate::platform_io::platform_destroy_window);
pio.platform_show_window = Some(crate::platform_io::platform_show_window);
pio.platform_set_window_pos = Some(crate::platform_io::platform_set_window_pos);
// pio.platform_get_window_pos = Some(crate::platform_io::platform_get_window_pos);
// since pio.platform_get_window_pos is not a C compatible function, cimgui provides an extra function to set it.
unsafe {
crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowPos(
pio,
@ -646,7 +686,7 @@ impl Context {
);
}
pio.platform_set_window_size = Some(crate::platform_io::platform_set_window_size);
// pio.platform_get_window_size = Some(crate::platform_io::platform_get_window_size);
// since pio.platform_get_window_size is not a C compatible function, cimgui provides an extra function to set it.
unsafe {
crate::platform_io::ImGuiPlatformIO_Set_Platform_GetWindowSize(
pio,
@ -665,6 +705,8 @@ impl Context {
self.platform_viewport_ctx = ctx;
}
/// Installs a [`RendererViewportBackend`](crate::RendererViewportBackend) that is used to
/// render extra viewports created by ImGui.
pub fn set_renderer_backend<T: crate::RendererViewportBackend>(&mut self, backend: T) {
let ctx = Box::new(UnsafeCell::new(crate::RendererViewportContext {
backend: Box::new(backend),
@ -682,11 +724,15 @@ impl Context {
self.renderer_viewport_ctx = ctx;
}
/// Updates the extra Viewports created by ImGui.
/// Has to be called every frame if Viewports are enabled.
pub fn update_platform_windows(&mut self) {
unsafe {
sys::igUpdatePlatformWindows();
}
}
/// Basically just calls the [`PlatformViewportBackend`](crate::PlatformViewportBackend) and [`RendererViewportBackend`](crate::RendererViewportBackend)
/// functions. If you render your extra viewports manually this function is not needed at all.
pub fn render_platform_windows_default(&mut self) {
unsafe {
sys::igRenderPlatformWindowsDefault(std::ptr::null_mut(), std::ptr::null_mut());

View File

@ -99,8 +99,10 @@ bitflags! {
const RENDERER_HAS_VTX_OFFSET = sys::ImGuiBackendFlags_RendererHasVtxOffset;
#[cfg(feature = "docking")]
/// Set if the platform backend supports viewports.
const PLATFORM_HAS_VIEWPORTS = sys::ImGuiBackendFlags_PlatformHasViewports;
#[cfg(feature = "docking")]
/// Set if the renderer backend supports viewports.
const RENDERER_HAS_VIEWPORTS = sys::ImGuiBackendFlags_RendererHasViewports;
}
}

View File

@ -8,6 +8,7 @@ use crate::{
Io, ViewportFlags,
};
/// Holds the information needed to enable multiple viewports.
#[repr(C)]
pub struct PlatformIo {
pub(crate) platform_create_window: Option<unsafe extern "C" fn(*mut Viewport)>,
@ -38,6 +39,8 @@ pub struct PlatformIo {
pub(crate) renderer_render_window: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
pub(crate) renderer_swap_buffers: Option<unsafe extern "C" fn(*mut Viewport, *mut c_void)>,
/// Holds information about the available monitors.
/// Should be initialized and updated by the [`PlatformViewportBackend`].
pub monitors: ImVector<PlatformMonitor>,
pub(crate) viewports: ImVector<*mut Viewport>,
@ -97,20 +100,55 @@ fn test_platform_io_memory_layout() {
assert_field_offset!(viewports, Viewports);
}
/// Trait holding functions needed when the platform integration supports viewports.
///
/// Register it via [`Context::set_platform_backend()`](crate::context::Context::set_platform_backend())
pub trait PlatformViewportBackend: 'static {
/// Called by imgui when a new [`Viewport`] is created.
///
/// # Notes
/// This function should initiate the creation of a platform window.
/// The window should be invisible.
fn create_window(&mut self, viewport: &mut Viewport);
/// Called by imgui when a [`Viewport`] is about to be destroyed.
///
/// # Notes
/// This function should initiate the destruction of the platform window.
fn destroy_window(&mut self, viewport: &mut Viewport);
/// Called by imgui to make a [`Viewport`] visible.
fn show_window(&mut self, viewport: &mut Viewport);
/// Called by imgui to reposition a [`Viewport`].
///
/// # Notes
/// `pos` specifies the position of the windows content area (excluding title bar etc.)
fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]);
/// Called by imgui to get the position of a [`Viewport`].
///
/// # Notes
/// You should return the position of the window's content area (excluding title bar etc.)
fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2];
/// Called by imgui to set the size of a [`Viewport`].
///
/// # Notes
/// `size` specifies the size of the window's content area (excluding title bar etc.)
fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]);
/// Called by imgui to get the size of a [`Viewport`].
///
/// # Notes
/// you should return the size of the window's content area (excluding title bar etc.)
fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2];
/// Called by imgui to make a [`Viewport`] steal the focus.
fn set_window_focus(&mut self, viewport: &mut Viewport);
/// Called by imgui to query whether a [`Viewport`] is in focus.
fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool;
/// Called by imgui to query whether a [`Viewport`] is minimized.
fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool;
/// Called by imgui to set a [`Viewport`] title.
fn set_window_title(&mut self, viewport: &mut Viewport, title: &str);
/// Called by imgui to set the opacity of an entire [`Viewport`].
///
/// If your backend does not support opactiy, it is safe to just do nothing in this function.
fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32);
fn update_window(&mut self, viewport: &mut Viewport);
fn render_window(&mut self, viewport: &mut Viewport);
fn swap_buffers(&mut self, viewport: &mut Viewport);
@ -122,15 +160,19 @@ pub trait PlatformViewportBackend: 'static {
) -> i32;
}
/// Used to get the current Contexts [`PlatformViewportContext`].
fn get_platform_ctx() -> &'static mut PlatformViewportContext {
unsafe {
// should be safe as it is impossible to call any imgui function on a non-active context.
&mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data
as *mut PlatformViewportContext)
}
}
/// Used to get the current Contexts [`RendererViewportContext`].
fn get_renderer_ctx() -> &'static mut RendererViewportContext {
unsafe {
// should be safe as it is impossible to call any imgui function on a non-active context.
&mut *((*(sys::igGetIO() as *const Io)).backend_platform_user_data
as *mut RendererViewportContext)
}
@ -226,6 +268,7 @@ pub(crate) extern "C" fn platform_create_vk_surface(
})
}
/// The default [`PlatformViewportBackend`], does nothing.
pub(crate) struct DummyPlatformViewportBackend {}
impl PlatformViewportBackend for DummyPlatformViewportBackend {
fn create_window(&mut self, _viewport: &mut Viewport) {
@ -298,6 +341,7 @@ impl PlatformViewportBackend for DummyPlatformViewportBackend {
}
}
/// Just holds a [`PlatformViewportBackend`].
pub(crate) struct PlatformViewportContext {
pub(crate) backend: Box<dyn PlatformViewportBackend>,
}
@ -310,9 +354,15 @@ impl PlatformViewportContext {
}
}
/// Trait that holds optional functions for a rendering backend to support multiple viewports.
///
/// It is completely fine to not use this Backend at all, as all functions are optional.
pub trait RendererViewportBackend: 'static {
/// Called after [`PlatformViewportBackend::create_window()`].
fn create_window(&mut self, viewport: &mut Viewport);
/// Called before [`PlatformViewportBackend::destroy_window()`].
fn destroy_window(&mut self, viewport: &mut Viewport);
/// Called after [`PlatformViewportBackend::set_window_size()`].
fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]);
fn render_window(&mut self, viewport: &mut Viewport);
fn swap_buffers(&mut self, viewport: &mut Viewport);
@ -340,6 +390,7 @@ pub(crate) extern "C" fn renderer_swap_buffers(viewport: *mut Viewport, _arg: *m
ctx.backend.swap_buffers(unsafe { &mut *viewport });
}
/// The default [`RendererViewportBackend`], does nothing.
pub(crate) struct DummyRendererViewportBackend {}
impl RendererViewportBackend for DummyRendererViewportBackend {
fn create_window(&mut self, _viewport: &mut Viewport) {
@ -363,6 +414,7 @@ impl RendererViewportBackend for DummyRendererViewportBackend {
}
}
/// Just holds a [`RendererViewportBackend`].
pub(crate) struct RendererViewportContext {
pub(crate) backend: Box<dyn RendererViewportBackend>,
}
@ -375,9 +427,12 @@ impl RendererViewportContext {
}
}
/// Describes an ImGui Viewport.
#[repr(C)]
pub struct Viewport {
/// The unique ID of this Viewport.
pub id: crate::Id,
/// Flags that describe how the Viewport should behave.
pub flags: ViewportFlags,
pub pos: [f32; 2],
pub size: [f32; 2],
@ -397,6 +452,7 @@ pub struct Viewport {
}
impl Viewport {
/// Returns the draw data of the respective Viewport.
pub fn draw_data(&self) -> &crate::DrawData {
unsafe { &*self.draw_data }
}
@ -443,11 +499,20 @@ fn test_viewport_memory_layout() {
assert_field_offset!(platform_request_close, PlatformRequestClose);
}
/// Describes a monitor that can be used by ImGui.
#[repr(C)]
pub struct PlatformMonitor {
/// Position of the monitor on the virtual desktop.
pub main_pos: [f32; 2],
/// Size of the monitor on the virtual desktop.
pub main_size: [f32; 2],
/// Working position of the monitor, should exclude task bar etc.
///
/// Set to `main_pos` if not known.
pub work_pos: [f32; 2],
/// Working size of the monitor, should exclude task bar etc.
///
/// Set to `work_size` if not known.
pub work_size: [f32; 2],
pub dpi_scale: f32,
}