use crate::sys;
use std::cell::UnsafeCell;
use std::ffi::{CStr, c_void};
#[repr(transparent)]
pub struct Viewport {
raw: UnsafeCell<sys::ImGuiViewport>,
}
const _: [(); std::mem::size_of::<sys::ImGuiViewport>()] = [(); std::mem::size_of::<Viewport>()];
const _: [(); std::mem::align_of::<sys::ImGuiViewport>()] = [(); std::mem::align_of::<Viewport>()];
impl Viewport {
#[inline]
fn inner(&self) -> &sys::ImGuiViewport {
unsafe { &*self.raw.get() }
}
#[inline]
fn inner_mut(&mut self) -> &mut sys::ImGuiViewport {
unsafe { &mut *self.raw.get() }
}
pub(crate) unsafe fn from_raw<'a>(raw: *const sys::ImGuiViewport) -> &'a Self {
unsafe { &*(raw as *const Self) }
}
pub unsafe fn from_raw_mut<'a>(raw: *mut sys::ImGuiViewport) -> &'a mut Self {
unsafe { &mut *(raw as *mut Self) }
}
pub fn as_raw(&self) -> *const sys::ImGuiViewport {
self.raw.get().cast_const()
}
pub fn as_raw_mut(&mut self) -> *mut sys::ImGuiViewport {
self.raw.get()
}
pub fn id(&self) -> sys::ImGuiID {
self.inner().ID
}
pub fn set_pos(&mut self, pos: [f32; 2]) {
self.inner_mut().Pos.x = pos[0];
self.inner_mut().Pos.y = pos[1];
}
pub fn pos(&self) -> [f32; 2] {
[self.inner().Pos.x, self.inner().Pos.y]
}
pub fn set_size(&mut self, size: [f32; 2]) {
self.inner_mut().Size.x = size[0];
self.inner_mut().Size.y = size[1];
}
pub fn size(&self) -> [f32; 2] {
[self.inner().Size.x, self.inner().Size.y]
}
pub fn work_pos(&self) -> [f32; 2] {
[self.inner().WorkPos.x, self.inner().WorkPos.y]
}
pub fn work_size(&self) -> [f32; 2] {
[self.inner().WorkSize.x, self.inner().WorkSize.y]
}
#[doc(alias = "GetCenter")]
pub fn center(&self) -> [f32; 2] {
unsafe {
let center = sys::ImGuiViewport_GetCenter(self.as_raw().cast_mut());
[center.x, center.y]
}
}
#[doc(alias = "GetWorkCenter")]
pub fn work_center(&self) -> [f32; 2] {
unsafe {
let center = sys::ImGuiViewport_GetWorkCenter(self.as_raw().cast_mut());
[center.x, center.y]
}
}
#[doc(alias = "GetDebugName")]
pub fn debug_name(&self) -> &str {
unsafe {
let ptr = sys::ImGuiViewport_GetDebugName(self.as_raw().cast_mut());
if ptr.is_null() {
""
} else {
CStr::from_ptr(ptr).to_str().unwrap_or("")
}
}
}
#[cfg(feature = "multi-viewport")]
pub fn is_main(&self) -> bool {
self.inner().ID == 0
|| (self.inner().Flags & (crate::ViewportFlags::IS_PLATFORM_WINDOW.bits())) == 0
}
#[cfg(not(feature = "multi-viewport"))]
pub fn is_main(&self) -> bool {
self.inner().ID == 0
}
#[cfg(feature = "multi-viewport")]
pub fn is_platform_window(&self) -> bool {
(self.inner().Flags & (crate::ViewportFlags::IS_PLATFORM_WINDOW.bits())) != 0
}
#[cfg(not(feature = "multi-viewport"))]
pub fn is_platform_window(&self) -> bool {
false
}
#[cfg(feature = "multi-viewport")]
pub fn is_platform_monitor(&self) -> bool {
(self.inner().Flags & (crate::ViewportFlags::IS_PLATFORM_MONITOR.bits())) != 0
}
#[cfg(not(feature = "multi-viewport"))]
pub fn is_platform_monitor(&self) -> bool {
false
}
#[cfg(feature = "multi-viewport")]
pub fn is_owned_by_app(&self) -> bool {
(self.inner().Flags & (crate::ViewportFlags::OWNED_BY_APP.bits())) != 0
}
#[cfg(not(feature = "multi-viewport"))]
pub fn is_owned_by_app(&self) -> bool {
false
}
pub fn platform_user_data(&self) -> *mut c_void {
self.inner().PlatformUserData
}
pub fn set_platform_user_data(&mut self, data: *mut c_void) {
self.inner_mut().PlatformUserData = data;
}
pub fn renderer_user_data(&self) -> *mut c_void {
self.inner().RendererUserData
}
pub fn set_renderer_user_data(&mut self, data: *mut c_void) {
self.inner_mut().RendererUserData = data;
}
pub fn platform_handle(&self) -> *mut c_void {
self.inner().PlatformHandle
}
pub fn set_platform_handle(&mut self, handle: *mut c_void) {
self.inner_mut().PlatformHandle = handle;
}
pub fn platform_handle_raw(&self) -> *mut c_void {
self.inner().PlatformHandleRaw
}
pub fn set_platform_handle_raw(&mut self, handle: *mut c_void) {
self.inner_mut().PlatformHandleRaw = handle;
}
pub fn platform_window_created(&self) -> bool {
self.inner().PlatformWindowCreated
}
pub fn set_platform_window_created(&mut self, created: bool) {
self.inner_mut().PlatformWindowCreated = created;
}
pub fn platform_request_move(&self) -> bool {
self.inner().PlatformRequestMove
}
pub fn set_platform_request_move(&mut self, request: bool) {
self.inner_mut().PlatformRequestMove = request;
}
pub fn platform_request_resize(&self) -> bool {
self.inner().PlatformRequestResize
}
pub fn set_platform_request_resize(&mut self, request: bool) {
self.inner_mut().PlatformRequestResize = request;
}
pub fn platform_request_close(&self) -> bool {
self.inner().PlatformRequestClose
}
pub fn set_platform_request_close(&mut self, request: bool) {
self.inner_mut().PlatformRequestClose = request;
}
pub fn flags(&self) -> sys::ImGuiViewportFlags {
self.inner().Flags
}
pub fn set_flags(&mut self, flags: sys::ImGuiViewportFlags) {
self.inner_mut().Flags = flags;
}
#[cfg(feature = "multi-viewport")]
pub fn dpi_scale(&self) -> f32 {
self.inner().DpiScale
}
#[cfg(feature = "multi-viewport")]
pub fn set_dpi_scale(&mut self, scale: f32) {
self.inner_mut().DpiScale = scale;
}
#[cfg(feature = "multi-viewport")]
pub fn parent_viewport_id(&self) -> sys::ImGuiID {
self.inner().ParentViewportId
}
#[cfg(feature = "multi-viewport")]
pub fn set_parent_viewport_id(&mut self, id: sys::ImGuiID) {
self.inner_mut().ParentViewportId = id;
}
#[cfg(feature = "multi-viewport")]
pub fn draw_data(&self) -> *mut sys::ImDrawData {
self.inner().DrawData
}
#[cfg(feature = "multi-viewport")]
pub fn draw_data_ref(&self) -> Option<&sys::ImDrawData> {
if self.inner().DrawData.is_null() {
None
} else {
Some(unsafe { &*self.inner().DrawData })
}
}
#[cfg(feature = "multi-viewport")]
pub fn framebuffer_scale(&self) -> [f32; 2] {
[
self.inner().FramebufferScale.x,
self.inner().FramebufferScale.y,
]
}
#[cfg(feature = "multi-viewport")]
pub fn set_framebuffer_scale(&mut self, scale: [f32; 2]) {
self.inner_mut().FramebufferScale.x = scale[0];
self.inner_mut().FramebufferScale.y = scale[1];
}
}
#[cfg(test)]
mod tests {
use super::Viewport;
use crate::Context;
use crate::sys;
use std::ffi::c_void;
fn new_viewport() -> *mut sys::ImGuiViewport {
unsafe {
let ptr = sys::ImGuiViewport_ImGuiViewport();
assert!(
!ptr.is_null(),
"ImGuiViewport_ImGuiViewport() returned null"
);
ptr
}
}
#[test]
fn viewport_center_and_work_center_follow_imgui_helpers() {
let raw = new_viewport();
unsafe {
(*raw).Pos.x = 10.0;
(*raw).Pos.y = 20.0;
(*raw).Size.x = 100.0;
(*raw).Size.y = 40.0;
(*raw).WorkPos.x = 30.0;
(*raw).WorkPos.y = 50.0;
(*raw).WorkSize.x = 20.0;
(*raw).WorkSize.y = 10.0;
let viewport = Viewport::from_raw_mut(raw);
assert_eq!(viewport.center(), [60.0, 40.0]);
assert_eq!(viewport.work_center(), [40.0, 55.0]);
sys::ImGuiViewport_destroy(raw);
}
}
#[test]
fn viewport_platform_handle_raw_roundtrips() {
let raw = new_viewport();
unsafe {
let viewport = Viewport::from_raw_mut(raw);
let handle = 0x1234usize as *mut c_void;
viewport.set_platform_handle_raw(handle);
assert_eq!(viewport.platform_handle_raw(), handle);
sys::ImGuiViewport_destroy(raw);
}
}
#[test]
fn main_viewport_exposes_debug_name() {
let mut ctx = Context::create();
let viewport = ctx.main_viewport();
assert!(!viewport.debug_name().is_empty());
}
}