mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 21:48:36 +00:00
Identified and implemented workaround for viewport callbacks not being triggered when windows are dragged outside the main window. Root cause: ConfigFlags::VIEWPORTS_ENABLE is reset after first render() call due to an issue in the imgui-rs bindings or Dear ImGui itself. Workaround: Re-apply the viewport flag before each new_frame() call using viewport_issue_fix::apply_viewport_fix(). Added: - viewport_issue_fix module with apply_viewport_fix() function - Debug and solution examples demonstrating the issue and fix - Integration tests for the workaround - Comprehensive documentation of findings in VIEWPORT_FIX_SUMMARY.md This is a temporary workaround until the root cause is fixed in imgui-rs or the Dear ImGui library. Co-Authored-By: Elias Stepanik <eliasstepanik@proton.me>
304 lines
11 KiB
Rust
304 lines
11 KiB
Rust
//! Debug example for viewport window creation issue
|
|
//! This example helps debug why viewport callbacks aren't triggered
|
|
|
|
use imgui::*;
|
|
use std::collections::HashMap;
|
|
use std::cell::RefCell;
|
|
|
|
/// Debug platform backend that logs all calls
|
|
#[cfg(feature = "docking")]
|
|
struct DebugPlatformBackend {
|
|
windows: HashMap<Id, DebugWindow>,
|
|
call_log: RefCell<Vec<String>>,
|
|
}
|
|
|
|
#[cfg(feature = "docking")]
|
|
struct DebugWindow {
|
|
id: Id,
|
|
created_at: std::time::Instant,
|
|
}
|
|
|
|
#[cfg(feature = "docking")]
|
|
impl DebugPlatformBackend {
|
|
fn new() -> Self {
|
|
Self {
|
|
windows: HashMap::new(),
|
|
call_log: RefCell::new(Vec::new()),
|
|
}
|
|
}
|
|
|
|
fn log(&self, msg: String) {
|
|
println!("[PLATFORM] {}", msg);
|
|
self.call_log.borrow_mut().push(msg);
|
|
}
|
|
}
|
|
|
|
#[cfg(feature = "docking")]
|
|
impl PlatformViewportBackend for DebugPlatformBackend {
|
|
fn create_window(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("=== CREATE_WINDOW CALLED ==="));
|
|
self.log(format!(" Viewport ID: {:?}", viewport.id));
|
|
self.log(format!(" Flags: {:?}", viewport.flags));
|
|
self.log(format!(" Position: {:?}", viewport.pos));
|
|
self.log(format!(" Size: {:?}", viewport.size));
|
|
self.log(format!(" DPI Scale: {}", viewport.dpi_scale));
|
|
self.log(format!(" platform_window_created: {}", viewport.platform_window_created));
|
|
|
|
self.windows.insert(
|
|
viewport.id,
|
|
DebugWindow {
|
|
id: viewport.id,
|
|
created_at: std::time::Instant::now(),
|
|
}
|
|
);
|
|
|
|
// Mark that we created the platform window
|
|
viewport.platform_window_created = true;
|
|
}
|
|
|
|
fn destroy_window(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("=== DESTROY_WINDOW CALLED === ID: {:?}", viewport.id));
|
|
self.windows.remove(&viewport.id);
|
|
}
|
|
|
|
fn show_window(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("SHOW_WINDOW: {:?}", viewport.id));
|
|
}
|
|
|
|
fn set_window_pos(&mut self, viewport: &mut Viewport, pos: [f32; 2]) {
|
|
self.log(format!("SET_WINDOW_POS: {:?} -> {:?}", viewport.id, pos));
|
|
}
|
|
|
|
fn get_window_pos(&mut self, viewport: &mut Viewport) -> [f32; 2] {
|
|
viewport.pos
|
|
}
|
|
|
|
fn set_window_size(&mut self, viewport: &mut Viewport, size: [f32; 2]) {
|
|
self.log(format!("SET_WINDOW_SIZE: {:?} -> {:?}", viewport.id, size));
|
|
}
|
|
|
|
fn get_window_size(&mut self, viewport: &mut Viewport) -> [f32; 2] {
|
|
viewport.size
|
|
}
|
|
|
|
fn set_window_focus(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("SET_WINDOW_FOCUS: {:?}", viewport.id));
|
|
}
|
|
|
|
fn get_window_focus(&mut self, viewport: &mut Viewport) -> bool {
|
|
let focused = !viewport.is_main();
|
|
self.log(format!("GET_WINDOW_FOCUS: {:?} = {}", viewport.id, focused));
|
|
focused
|
|
}
|
|
|
|
fn get_window_minimized(&mut self, viewport: &mut Viewport) -> bool {
|
|
self.log(format!("GET_WINDOW_MINIMIZED: {:?} = false", viewport.id));
|
|
false
|
|
}
|
|
|
|
fn set_window_title(&mut self, viewport: &mut Viewport, title: &str) {
|
|
self.log(format!("SET_WINDOW_TITLE: {:?} = '{}'", viewport.id, title));
|
|
}
|
|
|
|
fn set_window_alpha(&mut self, viewport: &mut Viewport, alpha: f32) {
|
|
self.log(format!("SET_WINDOW_ALPHA: {:?} = {}", viewport.id, alpha));
|
|
}
|
|
|
|
fn update_window(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("UPDATE_WINDOW: {:?}", viewport.id));
|
|
}
|
|
|
|
fn render_window(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("RENDER_WINDOW: {:?}", viewport.id));
|
|
}
|
|
|
|
fn swap_buffers(&mut self, viewport: &mut Viewport) {
|
|
self.log(format!("SWAP_BUFFERS: {:?}", viewport.id));
|
|
}
|
|
|
|
fn create_vk_surface(
|
|
&mut self,
|
|
viewport: &mut Viewport,
|
|
_instance: u64,
|
|
_out_surface: &mut u64,
|
|
) -> i32 {
|
|
self.log(format!("CREATE_VK_SURFACE: {:?}", viewport.id));
|
|
0
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
println!("=== VIEWPORT DEBUG EXAMPLE ===");
|
|
println!("This example helps debug viewport window creation issues.");
|
|
println!();
|
|
|
|
#[cfg(feature = "docking")]
|
|
{
|
|
// Create imgui context
|
|
let mut ctx = Context::create();
|
|
|
|
// Initialize IO properly
|
|
let io = ctx.io_mut();
|
|
io.display_size = [1280.0, 720.0];
|
|
io.delta_time = 1.0 / 60.0;
|
|
|
|
println!("Initial ConfigFlags: {:?}", io.config_flags);
|
|
|
|
// Enable viewports
|
|
println!("ConfigFlags before: {:?}", ctx.io().config_flags);
|
|
println!("Available flags: {:?}", ConfigFlags::all());
|
|
println!("VIEWPORTS_ENABLE flag value: {:?}", ConfigFlags::VIEWPORTS_ENABLE);
|
|
|
|
// Try using the fix function
|
|
ensure_viewport_flags(&mut ctx);
|
|
|
|
println!("ConfigFlags after ensure_viewport_flags: {:?}", ctx.io().config_flags);
|
|
|
|
// Double check it's actually set
|
|
if !ctx.io().config_flags.contains(ConfigFlags::VIEWPORTS_ENABLE) {
|
|
println!("ERROR: VIEWPORTS_ENABLE flag not set!");
|
|
} else {
|
|
println!("SUCCESS: VIEWPORTS_ENABLE flag is set!");
|
|
}
|
|
|
|
// Check C++ side directly
|
|
unsafe {
|
|
let io_ptr = sys::igGetIO();
|
|
if !io_ptr.is_null() {
|
|
println!("C++ ConfigFlags value: 0x{:08X}", (*io_ptr).ConfigFlags);
|
|
println!("VIEWPORTS_ENABLE constant: 0x{:08X}", sys::ImGuiConfigFlags_ViewportsEnable);
|
|
}
|
|
}
|
|
|
|
// Build font atlas
|
|
ctx.fonts().build_rgba32_texture();
|
|
|
|
// Set up debug platform backend
|
|
let platform_backend = DebugPlatformBackend::new();
|
|
ctx.set_platform_backend(platform_backend);
|
|
|
|
println!("\n=== STARTING FRAME SIMULATION ===\n");
|
|
|
|
// Check flag right before frames
|
|
println!("ConfigFlags before frame loop: {:?}", ctx.io().config_flags);
|
|
|
|
// Simulate several frames
|
|
for frame in 0..5 {
|
|
println!("\n>>> FRAME {} <<<", frame);
|
|
|
|
// Get main viewport info before new_frame
|
|
let main_vp_id;
|
|
let main_vp_pos;
|
|
let main_vp_size;
|
|
{
|
|
let main_vp = ctx.main_viewport();
|
|
main_vp_id = main_vp.id;
|
|
main_vp_pos = main_vp.pos;
|
|
main_vp_size = main_vp.size;
|
|
}
|
|
println!("Main viewport: ID={:?}, pos={:?}, size={:?}",
|
|
main_vp_id, main_vp_pos, main_vp_size);
|
|
|
|
// Check flags right before new_frame
|
|
println!("ConfigFlags RIGHT BEFORE new_frame: {:?}", ctx.io().config_flags);
|
|
|
|
let ui = ctx.new_frame();
|
|
|
|
// Window 1: Should be draggable outside
|
|
ui.window("Test Window 1")
|
|
.size([300.0, 200.0], Condition::FirstUseEver)
|
|
.position([100.0, 100.0], Condition::FirstUseEver)
|
|
.flags(WindowFlags::empty()) // No restrictive flags
|
|
.build(|| {
|
|
ui.text("This window should be draggable outside");
|
|
ui.text("Drag me outside the main window!");
|
|
|
|
let window_pos = ui.window_pos();
|
|
let window_size = ui.window_size();
|
|
ui.text(format!("Pos: {:?}", window_pos));
|
|
ui.text(format!("Size: {:?}", window_size));
|
|
});
|
|
|
|
// Window 2: Debug info window
|
|
ui.window("Debug Info")
|
|
.size([400.0, 300.0], Condition::FirstUseEver)
|
|
.position([500.0, 100.0], Condition::FirstUseEver)
|
|
.build(|| {
|
|
ui.text("Viewport Debug Information:");
|
|
ui.separator();
|
|
|
|
ui.text(format!("Frame: {}", frame));
|
|
|
|
// We'll check viewport info after render
|
|
ui.text("See console for viewport details");
|
|
});
|
|
|
|
// Simulate window being dragged outside on frame 2
|
|
if frame == 2 {
|
|
println!("\n!!! SIMULATING WINDOW DRAG OUTSIDE !!!");
|
|
// In a real scenario, the user would drag the window
|
|
// Here we're just changing position programmatically
|
|
ui.window("Forced Outside Window")
|
|
.position([1400.0, 100.0], Condition::Always)
|
|
.size([200.0, 100.0], Condition::FirstUseEver)
|
|
.flags(WindowFlags::empty())
|
|
.build(|| {
|
|
ui.text("I'm outside!");
|
|
});
|
|
}
|
|
|
|
// Render and update viewports
|
|
println!("\nCalling render()...");
|
|
let draw_data = ctx.render();
|
|
println!("Main viewport draw data: {} vertices, {} indices",
|
|
draw_data.total_vtx_count, draw_data.total_idx_count);
|
|
|
|
// Now check viewport info after render
|
|
println!("\nViewport info after render:");
|
|
println!("ConfigFlags: {:?}", ctx.io().config_flags);
|
|
if ctx.io().config_flags.contains(ConfigFlags::VIEWPORTS_ENABLE) {
|
|
println!("Viewports: ENABLED");
|
|
} else {
|
|
println!("Viewports: DISABLED");
|
|
}
|
|
|
|
// Check C++ side after render
|
|
unsafe {
|
|
let io_ptr = sys::igGetIO();
|
|
if !io_ptr.is_null() {
|
|
println!("C++ ConfigFlags after render: 0x{:08X}", (*io_ptr).ConfigFlags);
|
|
}
|
|
}
|
|
|
|
println!("\nPre-update viewport count: {}", ctx.viewports().count());
|
|
|
|
println!("\nCalling update_platform_windows()...");
|
|
ctx.update_platform_windows();
|
|
|
|
println!("\nPost-update viewport count: {}", ctx.viewports().count());
|
|
|
|
// Check all viewports after update
|
|
for (i, viewport) in ctx.viewports().enumerate() {
|
|
println!(" Viewport {}: ID={:?}, is_main={}, created={}",
|
|
i, viewport.id, viewport.is_main(), viewport.platform_window_created);
|
|
|
|
if let Some(dd) = viewport.draw_data() {
|
|
println!(" Has draw data: {} vertices", dd.total_vtx_count);
|
|
} else {
|
|
println!(" No draw data");
|
|
}
|
|
}
|
|
|
|
println!("\nCalling render_platform_windows_default()...");
|
|
ctx.render_platform_windows_default();
|
|
}
|
|
|
|
println!("\n=== SIMULATION COMPLETE ===");
|
|
}
|
|
|
|
#[cfg(not(feature = "docking"))]
|
|
{
|
|
println!("This example requires the 'docking' feature to be enabled.");
|
|
println!("Run with: cargo run --example viewport_debug --features docking");
|
|
}
|
|
} |