use std::cell::RefCell;
use std::ffi::{CStr, c_char, c_void};
use dear_imgui_rs::Context;
use winit::dpi::{LogicalPosition, LogicalSize};
use winit::event_loop::ActiveEventLoop;
use winit::window::{Window, WindowAttributes, WindowLevel};
thread_local! {
static EVENT_LOOP: RefCell<Option<*const ActiveEventLoop>> = const { RefCell::new(None) };
}
#[repr(C)]
pub struct ViewportData {
pub window: *mut Window, pub window_owned: bool, pub ignore_window_pos_event_frame: i32,
pub ignore_window_size_event_frame: i32,
}
impl Default for ViewportData {
fn default() -> Self {
Self::new()
}
}
impl ViewportData {
pub fn new() -> Self {
Self {
window: std::ptr::null_mut(),
window_owned: false,
ignore_window_pos_event_frame: -1,
ignore_window_size_event_frame: -1,
}
}
}
pub fn init_multi_viewport_support(_ctx: &mut Context, main_window: &Window) {
unsafe {
let pio = dear_imgui_rs::sys::igGetPlatformIO_Nil();
(*pio).Platform_CreateWindow = Some(winit_create_window);
(*pio).Platform_DestroyWindow = Some(winit_destroy_window);
(*pio).Platform_ShowWindow = Some(winit_show_window);
(*pio).Platform_SetWindowPos = Some(winit_set_window_pos);
(*pio).Platform_GetWindowPos = Some(winit_get_window_pos);
(*pio).Platform_SetWindowSize = Some(winit_set_window_size);
(*pio).Platform_GetWindowSize = Some(winit_get_window_size);
(*pio).Platform_SetWindowFocus = Some(winit_set_window_focus);
(*pio).Platform_GetWindowFocus = Some(winit_get_window_focus);
(*pio).Platform_GetWindowMinimized = Some(winit_get_window_minimized);
(*pio).Platform_SetWindowTitle = Some(winit_set_window_title);
(*pio).Platform_GetWindowFramebufferScale = Some(winit_get_window_framebuffer_scale);
(*pio).Platform_UpdateWindow = Some(winit_update_window);
setup_monitors();
}
init_main_viewport(main_window);
}
unsafe fn setup_monitors() {
}
fn init_main_viewport(main_window: &Window) {
unsafe {
let main_viewport = dear_imgui_rs::sys::igGetMainViewport();
let vd = Box::into_raw(Box::new(ViewportData::new()));
(*vd).window = main_window as *const Window as *mut Window;
(*vd).window_owned = false;
(*main_viewport).PlatformUserData = vd as *mut c_void;
(*main_viewport).PlatformHandle = main_window as *const Window as *mut c_void;
}
}
pub fn shutdown_multi_viewport_support() {
unsafe {
dear_imgui_rs::sys::igDestroyPlatformWindows();
}
}
pub fn set_event_loop(event_loop: &ActiveEventLoop) {
EVENT_LOOP.with(|el| {
*el.borrow_mut() = Some(event_loop as *const ActiveEventLoop);
});
}
unsafe extern "C" fn winit_create_window(vp: *mut dear_imgui_rs::sys::ImGuiViewport) {
if vp.is_null() {
return;
}
let event_loop = EVENT_LOOP.with(|el| el.borrow().map(|ptr| unsafe { &*ptr }));
let event_loop = match event_loop {
Some(el) => el,
None => return,
};
let vd = Box::into_raw(Box::new(ViewportData::new()));
let vp_ref = unsafe { &mut *vp };
vp_ref.PlatformUserData = vd as *mut c_void;
let viewport_flags = vp_ref.Flags;
let mut window_attrs = WindowAttributes::default()
.with_title("ImGui Viewport")
.with_inner_size(LogicalSize::new(vp_ref.Size.x as f64, vp_ref.Size.y as f64))
.with_position(winit::dpi::Position::Logical(LogicalPosition::new(
vp_ref.Pos.x as f64,
vp_ref.Pos.y as f64,
)))
.with_visible(false);
if viewport_flags & (dear_imgui_rs::sys::ImGuiViewportFlags_NoDecoration as i32) != 0 {
window_attrs = window_attrs.with_decorations(false);
}
if viewport_flags & (dear_imgui_rs::sys::ImGuiViewportFlags_TopMost as i32) != 0 {
window_attrs = window_attrs.with_window_level(WindowLevel::AlwaysOnTop);
}
match event_loop.create_window(window_attrs) {
Ok(window) => {
let window_ptr = Box::into_raw(Box::new(window));
unsafe {
(*vd).window = window_ptr;
(*vd).window_owned = true;
}
vp_ref.PlatformHandle = window_ptr as *mut c_void;
eprintln!("Warning: Event routing for viewport windows not yet implemented");
}
Err(_) => {
unsafe {
let _ = Box::from_raw(vd);
}
vp_ref.PlatformUserData = std::ptr::null_mut();
}
}
}
unsafe extern "C" fn winit_destroy_window(vp: *mut dear_imgui_rs::sys::ImGuiViewport) {
if vp.is_null() {
return;
}
let vp_ref = unsafe { &mut *vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_mut() } {
if vd.window_owned && !vd.window.is_null() {
unsafe {
let _ = Box::from_raw(vd.window);
}
}
vd.window = std::ptr::null_mut();
unsafe {
let _ = Box::from_raw(vd);
}
}
vp_ref.PlatformUserData = std::ptr::null_mut();
vp_ref.PlatformHandle = std::ptr::null_mut();
}
unsafe extern "C" fn winit_show_window(vp: *mut dear_imgui_rs::sys::ImGuiViewport) {
if vp.is_null() {
return;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
window.set_visible(true);
}
}
}
unsafe extern "C" fn winit_get_window_pos(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
) -> dear_imgui_rs::sys::ImVec2 {
if vp.is_null() {
return dear_imgui_rs::sys::ImVec2 { x: 0.0, y: 0.0 };
}
let vp_ref = unsafe { &*vp };
let viewport_id = vp_ref.ID;
if viewport_id == 0 {
return dear_imgui_rs::sys::ImVec2 { x: 0.0, y: 0.0 };
}
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
if let Ok(pos) = window.outer_position() {
return dear_imgui_rs::sys::ImVec2 {
x: pos.x as f32,
y: pos.y as f32,
};
}
}
}
dear_imgui_rs::sys::ImVec2 { x: 0.0, y: 0.0 }
}
unsafe extern "C" fn winit_set_window_pos(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
pos: dear_imgui_rs::sys::ImVec2,
) {
if vp.is_null() {
return;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_mut() } {
if let Some(window) = unsafe { vd.window.as_mut() } {
let position = LogicalPosition::new(pos.x as f64, pos.y as f64);
window.set_outer_position(position);
vd.ignore_window_pos_event_frame = dear_imgui_rs::sys::igGetFrameCount();
}
}
}
unsafe extern "C" fn winit_get_window_size(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
) -> dear_imgui_rs::sys::ImVec2 {
if vp.is_null() {
return dear_imgui_rs::sys::ImVec2 { x: 0.0, y: 0.0 };
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
let size = window.inner_size();
return dear_imgui_rs::sys::ImVec2 {
x: size.width as f32,
y: size.height as f32,
};
}
}
dear_imgui_rs::sys::ImVec2 { x: 0.0, y: 0.0 }
}
unsafe extern "C" fn winit_set_window_size(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
size: dear_imgui_rs::sys::ImVec2,
) {
if vp.is_null() {
return;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_mut() } {
if let Some(window) = unsafe { vd.window.as_mut() } {
let new_size = LogicalSize::new(size.x as f64, size.y as f64);
let _ = window.request_inner_size(new_size);
vd.ignore_window_size_event_frame = dear_imgui_rs::sys::igGetFrameCount();
}
}
}
unsafe extern "C" fn winit_set_window_focus(vp: *mut dear_imgui_rs::sys::ImGuiViewport) {
if vp.is_null() {
return;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
window.focus_window();
}
}
}
unsafe extern "C" fn winit_get_window_focus(vp: *mut dear_imgui_rs::sys::ImGuiViewport) -> bool {
if vp.is_null() {
return false;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
return window.has_focus();
}
}
false
}
unsafe extern "C" fn winit_get_window_minimized(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
) -> bool {
if vp.is_null() {
return false;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
return window.is_minimized().unwrap_or(false);
}
}
false
}
unsafe extern "C" fn winit_set_window_title(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
title: *const c_char,
) {
if vp.is_null() || title.is_null() {
return;
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
if let Ok(title_str) = unsafe { CStr::from_ptr(title) }.to_str() {
window.set_title(title_str);
}
}
}
}
unsafe extern "C" fn winit_get_window_framebuffer_scale(
vp: *mut dear_imgui_rs::sys::ImGuiViewport,
) -> dear_imgui_rs::sys::ImVec2 {
if vp.is_null() {
return dear_imgui_rs::sys::ImVec2 { x: 1.0, y: 1.0 };
}
let vp_ref = unsafe { &*vp };
let vd_ptr = vp_ref.PlatformUserData as *mut ViewportData;
if let Some(vd) = unsafe { vd_ptr.as_ref() } {
if let Some(window) = unsafe { vd.window.as_ref() } {
let scale = window.scale_factor() as f32;
return dear_imgui_rs::sys::ImVec2 { x: scale, y: scale };
}
}
dear_imgui_rs::sys::ImVec2 { x: 1.0, y: 1.0 }
}
unsafe extern "C" fn winit_update_window(vp: *mut dear_imgui_rs::sys::ImGuiViewport) {
if vp.is_null() {}
}