From 7f10cb35b2810e7084e2b7ba303832458249f016 Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Fri, 12 Jul 2019 18:46:11 +0300 Subject: [PATCH] Pull new window API from 0.1-dev --- imgui-examples/examples/color_button.rs | 12 +- imgui-examples/examples/custom_textures.rs | 4 +- imgui-examples/examples/hello_world.rs | 4 +- imgui-examples/examples/multiple_fonts.rs | 24 +- imgui-examples/examples/test_window_impl.rs | 39 +- .../examples/custom_textures.rs | 4 +- imgui-gfx-examples/examples/hello_world.rs | 4 +- src/child_frame.rs | 34 +- src/legacy.rs | 107 ++-- src/lib.rs | 71 +-- src/popup_modal.rs | 42 +- src/window.rs | 169 ------ src/window/content_region.rs | 29 + src/window/mod.rs | 557 ++++++++++++++++++ 14 files changed, 729 insertions(+), 371 deletions(-) delete mode 100644 src/window.rs create mode 100644 src/window/content_region.rs create mode 100644 src/window/mod.rs diff --git a/imgui-examples/examples/color_button.rs b/imgui-examples/examples/color_button.rs index f07e8cf..1e7388c 100644 --- a/imgui-examples/examples/color_button.rs +++ b/imgui-examples/examples/color_button.rs @@ -36,11 +36,11 @@ fn main() { } fn example_selector(state: &mut State, ui: &Ui) { - ui.window(im_str!("Color button examples")) + Window::new(im_str!("Color button examples")) .position([20.0, 20.0], Condition::Appearing) .size([700.0, 80.0], Condition::Appearing) .resizable(false) - .build(|| { + .build(ui, || { let ex1 = ui.radio_button(im_str!("Example 1: Basics"), &mut state.example, 1); let ex2 = ui.radio_button(im_str!("Example 2: Alpha component"), &mut state.example, 2); if ex1 || ex2 { @@ -50,10 +50,10 @@ fn example_selector(state: &mut State, ui: &Ui) { } fn example_1(state: &mut State, ui: &Ui) { - ui.window(im_str!("Example 1: Basics")) + Window::new(im_str!("Example 1: Basics")) .size([700.0, 300.0], Condition::Appearing) .position([20.0, 120.0], Condition::Appearing) - .build(|| { + .build(ui, || { ui.text_wrapped(im_str!( "Color button is a widget that displays a color value as a clickable rectangle. \ It also supports a tooltip with detailed information about the color value. \ @@ -98,10 +98,10 @@ fn example_1(state: &mut State, ui: &Ui) { } fn example_2(ui: &Ui) { - ui.window(im_str!("Example 2: Alpha component")) + Window::new(im_str!("Example 2: Alpha component")) .size([700.0, 320.0], Condition::Appearing) .position([20.0, 140.0], Condition::Appearing) - .build(|| { + .build(ui, || { ui.text_wrapped(im_str!( "The displayed color is passed to the button as four float values between \ 0.0 - 1.0 (RGBA). If you don't care about the alpha component, it can be \ diff --git a/imgui-examples/examples/custom_textures.rs b/imgui-examples/examples/custom_textures.rs index 8d95cae..91e57fc 100644 --- a/imgui-examples/examples/custom_textures.rs +++ b/imgui-examples/examples/custom_textures.rs @@ -68,9 +68,9 @@ impl CustomTexturesApp { } fn show_textures(&self, ui: &Ui) { - ui.window(im_str!("Hello textures")) + Window::new(im_str!("Hello textures")) .size([400.0, 600.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text(im_str!("Hello textures!")); if let Some(my_texture_id) = self.my_texture_id { ui.text("Some generated texture"); diff --git a/imgui-examples/examples/hello_world.rs b/imgui-examples/examples/hello_world.rs index aca7539..b744a76 100644 --- a/imgui-examples/examples/hello_world.rs +++ b/imgui-examples/examples/hello_world.rs @@ -5,9 +5,9 @@ mod support; fn main() { let system = support::init(file!()); system.main_loop(|_, ui| { - ui.window(im_str!("Hello world")) + Window::new(im_str!("Hello world")) .size([300.0, 100.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text(im_str!("Hello world!")); ui.text(im_str!("こんにちは世界!")); ui.text(im_str!("This...is...imgui-rs!")); diff --git a/imgui-examples/examples/multiple_fonts.rs b/imgui-examples/examples/multiple_fonts.rs index 78c3282..b570bb2 100644 --- a/imgui-examples/examples/multiple_fonts.rs +++ b/imgui-examples/examples/multiple_fonts.rs @@ -19,16 +19,18 @@ fn main() { .reload_font_texture(&mut system.imgui) .expect("Failed to reload fonts"); system.main_loop(|run, ui| { - ui.window(im_str!("Hello world")).opened(run).build(|| { - ui.text("Hello, I'm the default font!"); - let _roboto = ui.push_font(roboto); - ui.text("Hello, I'm Roboto Regular!"); - let _dokdo = ui.push_font(dokdo); - ui.text("Hello, I'm Dokdo Regular!"); - drop(_dokdo); - ui.text("Hello, I'm Roboto Regular again!"); - drop(_roboto); - ui.text("Hello, I'm the default font again!"); - }); + Window::new(im_str!("Hello world")) + .opened(run) + .build(ui, || { + ui.text("Hello, I'm the default font!"); + let _roboto = ui.push_font(roboto); + ui.text("Hello, I'm Roboto Regular!"); + let _dokdo = ui.push_font(dokdo); + ui.text("Hello, I'm Dokdo Regular!"); + drop(_dokdo); + ui.text("Hello, I'm Roboto Regular again!"); + drop(_roboto); + ui.text("Hello, I'm the default font again!"); + }); }); } diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index a517abf..594d0b1 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -244,15 +244,15 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.show_metrics_window(&mut state.show_app_metrics); } if state.show_app_style_editor { - ui.window(im_str!("Style Editor")) + Window::new(im_str!("Style Editor")) .opened(&mut state.show_app_style_editor) - .build(|| ui.show_default_style_editor()); + .build(ui, || ui.show_default_style_editor()); } if state.show_app_about { - ui.window(im_str!("About ImGui")) + Window::new(im_str!("About ImGui")) .always_auto_resize(true) .opened(&mut state.show_app_about) - .build(|| { + .build(ui, || { ui.text(format!("dear imgui, {}", imgui::dear_imgui_version())); ui.separator(); ui.text("By Omar Cornut and all github contributors."); @@ -271,8 +271,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ); } - let mut window = ui - .window(im_str!("ImGui Demo")) + let mut window = Window::new(im_str!("ImGui Demo")) .title_bar(!state.no_titlebar) .resizable(!state.no_resize) .movable(!state.no_move) @@ -283,7 +282,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { if !state.no_close { window = window.opened(opened) } - window.build(|| { + window.build(ui, || { let _token = ui.push_item_width(-140.0); ui.text(format!("dear imgui says hello. ({})", imgui::dear_imgui_version())); ui.menu_bar(|| { @@ -781,10 +780,10 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) { } fn show_example_app_auto_resize(ui: &Ui, state: &mut AutoResizeState, opened: &mut bool) { - ui.window(im_str!("Example: Auto-resizing window")) + Window::new(im_str!("Example: Auto-resizing window")) .opened(opened) .always_auto_resize(true) - .build(|| { + .build(ui, || { ui.text( "Window will resize every-ui to the size of its content. Note that you probably don't want to query the window size to @@ -802,7 +801,7 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) { const DISTANCE: f32 = 10.0; let window_pos = [DISTANCE, DISTANCE]; let _token = ui.push_style_color(StyleColor::WindowBg, [0.0, 0.0, 0.0, 0.3]); - ui.window(im_str!("Example: Fixed Overlay")) + Window::new(im_str!("Example: Fixed Overlay")) .opened(opened) .position(window_pos, Condition::Always) .title_bar(false) @@ -810,7 +809,7 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) { .always_auto_resize(true) .movable(false) .save_settings(false) - .build(|| { + .build(ui, || { ui.text( "Simple overlay\nin the corner of the screen.\n(right-click to change position)", ); @@ -824,17 +823,17 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) { } fn show_example_app_manipulating_window_title(ui: &Ui) { - ui.window(im_str!("Same title as another window##1")) + Window::new(im_str!("Same title as another window##1")) .position([100.0, 100.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text( "This is window 1. My title is the same as window 2, but my identifier is unique.", ); }); - ui.window(im_str!("Same title as another window##2")) + Window::new(im_str!("Same title as another window##2")) .position([100.0, 200.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text( "This is window 2. My title is the same as window 1, but my identifier is unique.", @@ -844,16 +843,16 @@ My title is the same as window 1, but my identifier is unique.", let ch_idx = (ui.time() / 0.25) as usize & 3; let num = ui.frame_count(); // The C++ version uses rand() here let title = im_str!("Animated title {} {}###AnimatedTitle", chars[ch_idx], num); - ui.window(&title) + Window::new(&title) .position([100.0, 300.0], Condition::FirstUseEver) - .build(|| ui.text("This window has a changing title")); + .build(ui, || ui.text("This window has a changing title")); } fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, opened: &mut bool) { - ui.window(im_str!("Example: Custom rendering")) + Window::new(im_str!("Example: Custom rendering")) .size([350.0, 560.0], Condition::FirstUseEver) .opened(opened) - .build(|| { + .build(ui, || { ui.text("Primitives"); // TODO: Add DragFloat to change value of sz ui.color_edit(im_str!("Color"), &mut state.col).build(); @@ -1011,7 +1010,7 @@ fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, // ImDrawList API uses screen coordinates! let canvas_pos = ui.get_cursor_screen_pos(); // Resize canvas to what's available - let mut canvas_size = ui.get_content_region_avail(); + let mut canvas_size = ui.content_region_avail(); if canvas_size[0] < 50.0 { canvas_size[0] = 50.0; } diff --git a/imgui-gfx-examples/examples/custom_textures.rs b/imgui-gfx-examples/examples/custom_textures.rs index fdbf59d..29381ea 100644 --- a/imgui-gfx-examples/examples/custom_textures.rs +++ b/imgui-gfx-examples/examples/custom_textures.rs @@ -62,9 +62,9 @@ impl CustomTexturesApp { } fn show_textures(&self, ui: &Ui) { - ui.window(im_str!("Hello textures")) + Window::new(im_str!("Hello textures")) .size([400.0, 600.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text(im_str!("Hello textures!")); if let Some(my_texture_id) = self.my_texture_id { ui.text("Some generated texture"); diff --git a/imgui-gfx-examples/examples/hello_world.rs b/imgui-gfx-examples/examples/hello_world.rs index cea8da9..4d94448 100644 --- a/imgui-gfx-examples/examples/hello_world.rs +++ b/imgui-gfx-examples/examples/hello_world.rs @@ -12,9 +12,9 @@ fn main() { let window_title = im_str!("Hello world (DirectX)"); system.main_loop(|_, ui| { - ui.window(window_title) + Window::new(window_title) .size([300.0, 100.0], Condition::FirstUseEver) - .build(|| { + .build(ui, || { ui.text(im_str!("Hello world!")); ui.text(im_str!("こんにちは世界!")); ui.text(im_str!("This...is...imgui-rs!")); diff --git a/src/child_frame.rs b/src/child_frame.rs index 8aab496..23eaa52 100644 --- a/src/child_frame.rs +++ b/src/child_frame.rs @@ -1,7 +1,7 @@ use std::marker::PhantomData; -use crate::legacy::ImGuiWindowFlags; use crate::sys; +use crate::window::WindowFlags; use crate::{ImStr, Ui}; #[must_use] @@ -9,7 +9,7 @@ pub struct ChildFrame<'ui, 'p> { name: &'p ImStr, size: [f32; 2], border: bool, - flags: ImGuiWindowFlags, + flags: WindowFlags, _phantom: PhantomData<&'ui Ui<'ui>>, } @@ -19,33 +19,33 @@ impl<'ui, 'p> ChildFrame<'ui, 'p> { name, size: size.into(), border: false, - flags: ImGuiWindowFlags::empty(), + flags: WindowFlags::empty(), _phantom: PhantomData, } } #[inline] pub fn movable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoMove, !value); + self.flags.set(WindowFlags::NO_MOVE, !value); self } #[inline] pub fn show_scrollbar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollbar, !value); + self.flags.set(WindowFlags::NO_SCROLLBAR, !value); self } #[inline] pub fn show_scrollbar_with_mouse(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollWithMouse, !value); + self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value); self } #[inline] pub fn collapsible(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoCollapse, !value); + self.flags.set(WindowFlags::NO_COLLAPSE, !value); self } #[inline] pub fn always_resizable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::AlwaysAutoResize, value); + self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value); self } #[inline] @@ -55,46 +55,46 @@ impl<'ui, 'p> ChildFrame<'ui, 'p> { } #[inline] pub fn input_allow(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoInputs, !value); + self.flags.set(WindowFlags::NO_INPUTS, !value); self } #[inline] pub fn show_menu(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::MenuBar, value); + self.flags.set(WindowFlags::MENU_BAR, value); self } #[inline] pub fn scrollbar_horizontal(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::HorizontalScrollbar, value); + self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value); self } #[inline] pub fn focus_on_appearing(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoFocusOnAppearing, !value); + self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value); self } #[inline] pub fn bring_to_front_on_focus(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::NoBringToFrontOnFocus, !value); + .set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value); self } #[inline] pub fn always_show_vertical_scroll_bar(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysVerticalScrollbar, value); + .set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value); self } #[inline] pub fn always_show_horizontal_scroll_bar(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysHorizontalScrollbar, value); + .set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value); self } #[inline] pub fn always_use_window_padding(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysUseWindowPadding, value); + .set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value); self } pub fn build(self, f: F) { @@ -103,7 +103,7 @@ impl<'ui, 'p> ChildFrame<'ui, 'p> { self.name.as_ptr(), self.size.into(), self.border, - self.flags.bits(), + self.flags.bits() as i32, ) }; if render_child_frame { diff --git a/src/legacy.rs b/src/legacy.rs index 65e7677..272a5ee 100644 --- a/src/legacy.rs +++ b/src/legacy.rs @@ -2,6 +2,10 @@ use bitflags::bitflags; use std::os::raw::c_int; +use crate::string::ImStr; +use crate::window::{Window, WindowFlags}; +use crate::Ui; + bitflags!( /// Color edit flags #[repr(C)] @@ -295,57 +299,56 @@ bitflags!( } ); -bitflags!( - /// Window flags - #[repr(C)] - pub struct ImGuiWindowFlags: c_int { - /// Disable title-bar. - const NoTitleBar = 1; - /// Disable user resizing with the lower-right grip. - const NoResize = 1 << 1; - /// Disable user moving the window. - const NoMove = 1 << 2; - /// Disable scrollbars (window can still scroll with mouse or programatically). - const NoScrollbar = 1 << 3; - /// Disable user vertically scrolling with mouse wheel. On child window, mouse wheel will - /// be forwarded to the parent unless NoScrollbar is also set. - const NoScrollWithMouse = 1 << 4; - /// Disable user collapsing window by double-clicking on it. - const NoCollapse = 1 << 5; - /// Resize every window to its content every frame. - const AlwaysAutoResize = 1 << 6; - /// Disable drawing background color (WindowBg, etc.) and outside border - const NoBackground = 1 << 7; - /// Never load/save settings in .ini file. - const NoSavedSettings = 1 << 8; - /// Disable catching mouse, hovering test with pass through. - const NoMouseInputs = 1 << 9; - /// Has a menu-bar. - const MenuBar = 1 << 10; - /// Allow horizontal scrollbar to appear (off by default). - const HorizontalScrollbar = 1 << 11; - /// Disable taking focus when transitioning from hidden to visible state. - const NoFocusOnAppearing = 1 << 12; - /// Disable bringing window to front when taking focus (e.g. clicking on it or - /// programmatically giving it focus). - const NoBringToFrontOnFocus = 1 << 13; - /// Always show vertical scrollbar. - const AlwaysVerticalScrollbar = 1 << 14; - /// Always show horizontal scrollbar. - const AlwaysHorizontalScrollbar = 1<< 15; - /// Ensure child windows without border use window padding (ignored by default for - /// non-bordered child windows, because more convenient). - const AlwaysUseWindowPadding = 1 << 16; - /// No gamepad/keyboard navigation within the window. - const NoNavInputs = 1 << 18; - /// No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by - /// CTRL+TAB). - const NoNavFocus = 1 << 19; +#[deprecated(since = "0.2.0", note = "use WindowFlags instead")] +pub type ImGuiWindowFlags = WindowFlags; - const NoNav = ImGuiWindowFlags::NoNavInputs.bits | ImGuiWindowFlags::NoNavFocus.bits; - const NoDecoration = ImGuiWindowFlags::NoTitleBar.bits | ImGuiWindowFlags::NoResize.bits - | ImGuiWindowFlags::NoScrollbar.bits | ImGuiWindowFlags::NoCollapse.bits; - const NoInputs = ImGuiWindowFlags::NoMouseInputs.bits | ImGuiWindowFlags::NoNavInputs.bits - | ImGuiWindowFlags::NoNavFocus.bits; +impl<'ui> Ui<'ui> { + #[deprecated(since = "0.2.0", note = "use imgui::Window::new(...) instead")] + pub fn window<'p>(&self, name: &'p ImStr) -> Window<'p> { + Window::new(name) } -); + #[deprecated(since = "0.2.0", note = "use Ui::window_size instead")] + pub fn get_window_size(&self) -> [f32; 2] { + let size = unsafe { sys::igGetWindowSize_nonUDT2() }; + size.into() + } + #[deprecated(since = "0.2.0", note = "use Ui::window_pos instead")] + pub fn get_window_pos(&self) -> [f32; 2] { + let size = unsafe { sys::igGetWindowPos_nonUDT2() }; + size.into() + } + #[deprecated(since = "0.2.0", note = "use Ui::content_region_max instead")] + pub fn get_content_region_max(&self) -> [f32; 2] { + let size = unsafe { sys::igGetContentRegionMax_nonUDT2() }; + size.into() + } + #[deprecated(since = "0.2.0", note = "use Ui::content_region_avail instead")] + pub fn get_content_region_avail(&self) -> [f32; 2] { + let size = unsafe { sys::igGetContentRegionAvail_nonUDT2() }; + size.into() + } + #[deprecated(since = "0.2.0", note = "use Ui::window_content_region_min instead")] + pub fn get_window_content_region_min(&self) -> [f32; 2] { + let size = unsafe { sys::igGetWindowContentRegionMin_nonUDT2() }; + size.into() + } + #[deprecated(since = "0.2.0", note = "use Ui::window_content_region_max instead")] + pub fn get_window_content_region_max(&self) -> [f32; 2] { + let size = unsafe { sys::igGetWindowContentRegionMax_nonUDT2() }; + size.into() + } + #[deprecated( + since = "0.2.0", + note = "use Ui::is_window_focused(WindowFlags::RootWindow) instead" + )] + pub fn is_root_window_focused(&self) -> bool { + unsafe { sys::igIsWindowFocused(ImGuiFocusedFlags::RootWindow.bits()) } + } + #[deprecated( + since = "0.2.0", + note = "use Ui::is_window_focused(WindowFlags::ChildWindows) instead" + )] + pub fn is_child_window_focused(&self) -> bool { + unsafe { sys::igIsWindowFocused(ImGuiFocusedFlags::ChildWindows.bits()) } + } +} diff --git a/src/lib.rs b/src/lib.rs index 5493211..b8f48ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ pub use self::stacks::*; pub use self::string::*; pub use self::style::*; pub use self::trees::{CollapsingHeader, TreeNode}; -pub use self::window::Window; +pub use self::window::*; pub use self::window_draw_list::{ChannelsSplit, ImColor, WindowDrawList}; use internal::RawCast; @@ -200,33 +200,6 @@ impl<'ui> Ui<'ui> { } } -// Window -impl<'ui> Ui<'ui> { - pub fn window<'p>(&self, name: &'p ImStr) -> Window<'ui, 'p> { - Window::new(self, name) - } - /// Get current window's size in pixels - pub fn get_window_size(&self) -> [f32; 2] { - let size = unsafe { sys::igGetWindowSize_nonUDT2() }; - size.into() - } - /// Get current window's position in pixels - pub fn get_window_pos(&self) -> [f32; 2] { - let size = unsafe { sys::igGetWindowPos_nonUDT2() }; - size.into() - } - - pub fn get_window_content_region_min(&self) -> [f32; 2] { - let size = unsafe { sys::igGetWindowContentRegionMin_nonUDT2() }; - size.into() - } - - pub fn get_window_content_region_max(&self) -> [f32; 2] { - let size = unsafe { sys::igGetWindowContentRegionMax_nonUDT2() }; - size.into() - } -} - // Layout impl<'ui> Ui<'ui> { pub fn columns<'p>(&self, count: i32, id: &'p ImStr, border: bool) { @@ -284,18 +257,6 @@ impl<'ui> Ui<'ui> { pub fn set_cursor_pos(&self, pos: [f32; 2]) { unsafe { sys::igSetCursorPos(pos.into()) } } - - pub fn get_content_region_max(&self) -> [f32; 2] { - let size = unsafe { sys::igGetContentRegionMax_nonUDT2() }; - size.into() - } - - /// Get available space left between the cursor and the edges of the current - /// window. - pub fn get_content_region_avail(&self) -> [f32; 2] { - let size = unsafe { sys::igGetContentRegionAvail_nonUDT2() }; - size.into() - } } pub enum ImId<'a> { @@ -697,7 +658,7 @@ impl<'ui> Ui<'ui> { F: FnOnce(), { let render = - unsafe { sys::igBeginPopup(str_id.as_ptr(), ImGuiWindowFlags::empty().bits()) }; + unsafe { sys::igBeginPopup(str_id.as_ptr(), WindowFlags::empty().bits() as i32) }; if render { f(); unsafe { sys::igEndPopup() }; @@ -873,10 +834,10 @@ impl<'ui> Ui<'ui> { /// # use imgui::*; /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(); - /// ui.window(im_str!("ChatWindow")) + /// Window::new(im_str!("ChatWindow")) /// .title_bar(true) /// .scrollable(false) - /// .build(|| { + /// .build(&ui, || { /// ui.separator(); /// /// ui.child_frame(im_str!("child frame"), [400.0, 100.0]) @@ -914,30 +875,6 @@ impl<'ui> Ui<'ui> { unsafe { sys::igIsItemHovered(flags.bits()) } } - /// Return `true` if the current window is being hovered by the mouse. - pub fn is_window_hovered(&self) -> bool { - unsafe { sys::igIsWindowHovered(ImGuiHoveredFlags::empty().bits()) } - } - - pub fn is_window_hovered_with_flags(&self, flags: ImGuiHoveredFlags) -> bool { - unsafe { sys::igIsWindowHovered(flags.bits()) } - } - - /// Return `true` if the current window is currently focused. - pub fn is_window_focused(&self) -> bool { - unsafe { sys::igIsWindowFocused(ImGuiFocusedFlags::RootAndChildWindows.bits()) } - } - - /// Return `true` if the current root window is currently focused. - pub fn is_root_window_focused(&self) -> bool { - unsafe { sys::igIsWindowFocused(ImGuiFocusedFlags::RootWindow.bits()) } - } - - /// Return `true` if the current child window is currently focused. - pub fn is_child_window_focused(&self) -> bool { - unsafe { sys::igIsWindowFocused(ImGuiFocusedFlags::ChildWindows.bits()) } - } - /// Returns `true` if the last item is being active. pub fn is_item_active(&self) -> bool { unsafe { sys::igIsItemActive() } diff --git a/src/popup_modal.rs b/src/popup_modal.rs index d41c7ce..0cb668a 100644 --- a/src/popup_modal.rs +++ b/src/popup_modal.rs @@ -1,8 +1,8 @@ use std::marker::PhantomData; use std::ptr; -use crate::legacy::ImGuiWindowFlags; use crate::sys; +use crate::window::WindowFlags; use crate::{ImStr, Ui}; /// Created by call to [`Ui::popup_modal`]. @@ -10,7 +10,7 @@ use crate::{ImStr, Ui}; pub struct PopupModal<'ui, 'p> { label: &'p ImStr, opened: Option<&'p mut bool>, - flags: ImGuiWindowFlags, + flags: WindowFlags, _phantom: PhantomData<&'ui Ui<'ui>>, } @@ -19,7 +19,7 @@ impl<'ui, 'p> PopupModal<'ui, 'p> { PopupModal { label, opened: None, - flags: ImGuiWindowFlags::empty(), + flags: WindowFlags::empty(), _phantom: PhantomData, } } @@ -29,76 +29,76 @@ impl<'ui, 'p> PopupModal<'ui, 'p> { self.opened = Some(opened); self } - pub fn flags(mut self, flags: ImGuiWindowFlags) -> Self { + pub fn flags(mut self, flags: WindowFlags) -> Self { self.flags = flags; self } pub fn title_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoTitleBar, !value); + self.flags.set(WindowFlags::NO_TITLE_BAR, !value); self } pub fn resizable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoResize, !value); + self.flags.set(WindowFlags::NO_RESIZE, !value); self } pub fn movable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoMove, !value); + self.flags.set(WindowFlags::NO_MOVE, !value); self } pub fn scroll_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollbar, !value); + self.flags.set(WindowFlags::NO_SCROLLBAR, !value); self } pub fn scrollable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollWithMouse, !value); + self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value); self } pub fn collapsible(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoCollapse, !value); + self.flags.set(WindowFlags::NO_COLLAPSE, !value); self } pub fn always_auto_resize(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::AlwaysAutoResize, value); + self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value); self } pub fn save_settings(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoSavedSettings, !value); + self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value); self } pub fn inputs(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoInputs, !value); + self.flags.set(WindowFlags::NO_INPUTS, !value); self } pub fn menu_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::MenuBar, value); + self.flags.set(WindowFlags::MENU_BAR, value); self } pub fn horizontal_scrollbar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::HorizontalScrollbar, value); + self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value); self } pub fn no_focus_on_appearing(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoFocusOnAppearing, value); + self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, value); self } pub fn no_bring_to_front_on_focus(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::NoBringToFrontOnFocus, value); + .set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, value); self } pub fn always_vertical_scrollbar(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysVerticalScrollbar, value); + .set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value); self } pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysHorizontalScrollbar, value); + .set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value); self } pub fn always_use_window_padding(mut self, value: bool) -> Self { self.flags - .set(ImGuiWindowFlags::AlwaysUseWindowPadding, value); + .set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value); self } /// Consume and draw the PopupModal. @@ -109,7 +109,7 @@ impl<'ui, 'p> PopupModal<'ui, 'p> { self.opened .map(|x| x as *mut bool) .unwrap_or(ptr::null_mut()), - self.flags.bits(), + self.flags.bits() as i32, ) }; if render { diff --git a/src/window.rs b/src/window.rs deleted file mode 100644 index 138c6b7..0000000 --- a/src/window.rs +++ /dev/null @@ -1,169 +0,0 @@ -use std::marker::PhantomData; -use std::ptr; -use sys; - -use crate::legacy::ImGuiWindowFlags; -use crate::{Condition, ImStr, Ui}; - -#[must_use] -pub struct Window<'ui, 'p> { - pos: [f32; 2], - pos_cond: Condition, - pos_pivot: [f32; 2], - size: [f32; 2], - size_cond: Condition, - name: &'p ImStr, - opened: Option<&'p mut bool>, - flags: ImGuiWindowFlags, - _phantom: PhantomData<&'ui Ui<'ui>>, -} - -impl<'ui, 'p> Window<'ui, 'p> { - pub fn new(_: &Ui<'ui>, name: &'p ImStr) -> Window<'ui, 'p> { - Window { - pos: [0.0, 0.0], - pos_cond: Condition::Never, - pos_pivot: [0.0, 0.0], - size: [0.0, 0.0], - size_cond: Condition::Never, - name, - opened: None, - flags: ImGuiWindowFlags::empty(), - _phantom: PhantomData, - } - } - #[inline] - pub fn position(mut self, pos: [f32; 2], cond: Condition) -> Self { - self.pos = pos; - self.pos_cond = cond; - self - } - #[inline] - pub fn position_pivot(mut self, pivot: [f32; 2]) -> Self { - self.pos_pivot = pivot; - self - } - #[inline] - pub fn size(mut self, size: [f32; 2], cond: Condition) -> Self { - self.size = size; - self.size_cond = cond; - self - } - #[inline] - pub fn opened(mut self, opened: &'p mut bool) -> Self { - self.opened = Some(opened); - self - } - #[inline] - pub fn flags(mut self, flags: ImGuiWindowFlags) -> Self { - self.flags = flags; - self - } - #[inline] - pub fn title_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoTitleBar, !value); - self - } - #[inline] - pub fn resizable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoResize, !value); - self - } - #[inline] - pub fn movable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoMove, !value); - self - } - #[inline] - pub fn scroll_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollbar, !value); - self - } - #[inline] - pub fn scrollable(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoScrollWithMouse, !value); - self - } - #[inline] - pub fn collapsible(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoCollapse, !value); - self - } - #[inline] - pub fn always_auto_resize(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::AlwaysAutoResize, value); - self - } - #[inline] - pub fn save_settings(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoSavedSettings, !value); - self - } - #[inline] - pub fn inputs(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoInputs, !value); - self - } - #[inline] - pub fn menu_bar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::MenuBar, value); - self - } - #[inline] - pub fn horizontal_scrollbar(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::HorizontalScrollbar, value); - self - } - #[inline] - pub fn no_focus_on_appearing(mut self, value: bool) -> Self { - self.flags.set(ImGuiWindowFlags::NoFocusOnAppearing, value); - self - } - #[inline] - pub fn no_bring_to_front_on_focus(mut self, value: bool) -> Self { - self.flags - .set(ImGuiWindowFlags::NoBringToFrontOnFocus, value); - self - } - #[inline] - pub fn always_vertical_scrollbar(mut self, value: bool) -> Self { - self.flags - .set(ImGuiWindowFlags::AlwaysVerticalScrollbar, value); - self - } - #[inline] - pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self { - self.flags - .set(ImGuiWindowFlags::AlwaysHorizontalScrollbar, value); - self - } - #[inline] - pub fn always_use_window_padding(mut self, value: bool) -> Self { - self.flags - .set(ImGuiWindowFlags::AlwaysUseWindowPadding, value); - self - } - pub fn build(self, f: F) { - let render = unsafe { - if self.pos_cond != Condition::Never { - sys::igSetNextWindowPos(self.pos.into(), self.pos_cond as _, self.pos_pivot.into()); - } - if self.size_cond != Condition::Never { - sys::igSetNextWindowSize(self.size.into(), self.size_cond as _); - } - sys::igBegin( - self.name.as_ptr(), - self.opened - .map(|x| x as *mut bool) - .unwrap_or(ptr::null_mut()), - self.flags.bits(), - ) - }; - if render { - f(); - } - unsafe { - sys::igEnd(); - }; - } -} diff --git a/src/window/content_region.rs b/src/window/content_region.rs new file mode 100644 index 0000000..a5df9fa --- /dev/null +++ b/src/window/content_region.rs @@ -0,0 +1,29 @@ +use crate::sys; +use crate::Ui; + +/// # Content region +impl<'ui> Ui<'ui> { + /// Returns the current content boundaries in *window coordinates* + pub fn content_region_max(&self) -> [f32; 2] { + unsafe { sys::igGetContentRegionMax_nonUDT2().into() } + } + /// Equal to `ui.content_region_max()` - `ui.cursor_pos()` + pub fn content_region_avail(&self) -> [f32; 2] { + unsafe { sys::igGetContentRegionAvail_nonUDT2().into() } + } + /// Content boundaries min in *window coordinates*. + /// + /// Roughly equal to [0.0, 0.0] - scroll. + pub fn window_content_region_min(&self) -> [f32; 2] { + unsafe { sys::igGetWindowContentRegionMin_nonUDT2().into() } + } + /// Content boundaries max in *window coordinates*. + /// + /// Roughly equal to [0.0, 0.0] + size - scroll. + pub fn window_content_region_max(&self) -> [f32; 2] { + unsafe { sys::igGetWindowContentRegionMax_nonUDT2().into() } + } + pub fn window_content_region_width(&self) -> f32 { + unsafe { sys::igGetWindowContentRegionWidth() } + } +} diff --git a/src/window/mod.rs b/src/window/mod.rs new file mode 100644 index 0000000..949aef6 --- /dev/null +++ b/src/window/mod.rs @@ -0,0 +1,557 @@ +use bitflags::bitflags; +use std::f32; +use std::marker::PhantomData; +use std::ptr; + +use crate::string::ImStr; +use crate::sys; +use crate::{Condition, Ui}; + +pub(crate) mod content_region; + +bitflags! { + /// Window hover check option flags + #[repr(transparent)] + pub struct WindowHoveredFlags: u32 { + /// Return true if any child of the window is hovered + const CHILD_WINDOWS = sys::ImGuiHoveredFlags_ChildWindows; + /// Test from root window (top-most parent of the current hierarchy) + const ROOT_WINDOW = sys::ImGuiHoveredFlags_RootWindow; + /// Return true if any window is hovered + const ANY_WINDOW = sys::ImGuiHoveredFlags_AnyWindow; + /// Return true even if a popup window is blocking access to this window + const ALLOW_WHEN_BLOCKED_BY_POPUP = sys::ImGuiHoveredFlags_AllowWhenBlockedByPopup; + /// Return true even if an active item is blocking access to this window + const ALLOW_WHEN_BLOCKED_BY_ACTIVE_ITEM = sys::ImGuiHoveredFlags_AllowWhenBlockedByActiveItem; + /// Test from root window, and return true if any child is hovered + const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits; + } +} + +bitflags! { + /// Window focus check option flags + #[repr(transparent)] + pub struct WindowFocusedFlags: u32 { + /// Return true if any child of the window is focused + const CHILD_WINDOWS = sys::ImGuiFocusedFlags_ChildWindows; + /// Test from root window (top-most parent of the current hierarchy) + const ROOT_WINDOW = sys::ImGuiFocusedFlags_RootWindow; + /// Return true if any window is focused + const ANY_WINDOW = sys::ImGuiFocusedFlags_AnyWindow; + /// Test from root window, and return true if any child is focused + const ROOT_AND_CHILD_WINDOWS = Self::ROOT_WINDOW.bits | Self::CHILD_WINDOWS.bits; + } +} + +bitflags! { + /// Configuration flags for windows + #[repr(transparent)] + pub struct WindowFlags: u32 { + /// Disable the title bar + const NO_TITLE_BAR = sys::ImGuiWindowFlags_NoTitleBar; + /// Disable resizing with the lower-right grip + const NO_RESIZE = sys::ImGuiWindowFlags_NoResize; + /// Disable moving the window + const NO_MOVE = sys::ImGuiWindowFlags_NoMove; + /// Disable scrollbars (scrolling is still possible with the mouse or programmatically) + const NO_SCROLLBAR = sys::ImGuiWindowFlags_NoScrollbar; + /// Disable vertical scrolling with the mouse wheel. + /// + /// On child window, the mouse wheel will be forwarded to the parent unless `NO_SCROLLBAR` + /// is also set. + const NO_SCROLL_WITH_MOUSE = sys::ImGuiWindowFlags_NoScrollWithMouse; + /// Disable collapsing the window by double-clicking it + const NO_COLLAPSE = sys::ImGuiWindowFlags_NoCollapse; + /// Resize the window to its content on every frame + const ALWAYS_AUTO_RESIZE = sys::ImGuiWindowFlags_AlwaysAutoResize; + /// Disable drawing of background color and outside border + const NO_BACKGROUND = sys::ImGuiWindowFlags_NoBackground; + /// Never load/save settings + const NO_SAVED_SETTINGS = sys::ImGuiWindowFlags_NoSavedSettings; + /// Disable catching mouse input. Hovering test will pass through + const NO_MOUSE_INPUTS = sys::ImGuiWindowFlags_NoMouseInputs; + /// Show a menu bar + const MENU_BAR = sys::ImGuiWindowFlags_MenuBar; + /// Allow horizontal scrollbar to appear + const HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_HorizontalScrollbar; + /// Disable taking focus when transitioning from hidden to visible state + const NO_FOCUS_ON_APPEARING = sys::ImGuiWindowFlags_NoFocusOnAppearing; + /// Disable bringing window to front when taking focus (e.g. clicking it or + /// programmatically giving it focus) + const NO_BRING_TO_FRONT_ON_FOCUS = sys::ImGuiWindowFlags_NoBringToFrontOnFocus; + /// Always show vertical scrollbar + const ALWAYS_VERTICAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysVerticalScrollbar; + /// Always show horizontal scrollbar + const ALWAYS_HORIZONTAL_SCROLLBAR = sys::ImGuiWindowFlags_AlwaysHorizontalScrollbar; + /// Ensure child windows without border use `style.window_padding` + const ALWAYS_USE_WINDOW_PADDING = sys::ImGuiWindowFlags_AlwaysUseWindowPadding; + /// Disable gamepad/keyboard navigation within the window + const NO_NAV_INPUTS = sys::ImGuiWindowFlags_NoNavInputs; + /// No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by + /// CTRL+TAB) + const NO_NAV_FOCUS = sys::ImGuiWindowFlags_NoNavFocus; + /// Append '*' to title without affecting the ID, as a convenience + const UNSAVED_DOCUMENT = sys::ImGuiWindowFlags_UnsavedDocument; + /// Disable gamepad/keyboard navigation and focusing. + /// + /// Shorthand for `WindowFlags::NO_NAV_INPUTS | WindowFlags::NO_NAV_FOCUS`. + const NO_NAV = sys::ImGuiWindowFlags_NoNav; + /// Disable all window decorations. + /// + /// Shorthand for `WindowFlags::NO_TITLE_BAR | WindowFlags::NO_RESIZE | + /// WindowFlags::NO_SCROLLBAR | WindowFlags::NO_COLLAPSE`. + const NO_DECORATION = sys::ImGuiWindowFlags_NoDecoration; + /// Don't handle input. + /// + /// Shorthand for `WindowFlags::NO_MOUSE_INPUTS | WindowFlags::NO_NAV_INPUTS | + /// WindowFlags::NO_NAV_FOCUS`. + const NO_INPUTS = sys::ImGuiWindowFlags_NoInputs; + } +} + +/// # Window utilities +impl<'ui> Ui<'ui> { + /// Returns true if the current window appeared during this frame + pub fn is_window_appearing(&self) -> bool { + unsafe { sys::igIsWindowAppearing() } + } + /// Returns true if the current window is in collapsed state (= only the title bar is visible) + pub fn is_window_collapsed(&self) -> bool { + unsafe { sys::igIsWindowCollapsed() } + } + /// Returns true if the current window is focused + pub fn is_window_focused(&self) -> bool { + unsafe { sys::igIsWindowFocused(0) } + } + /// Returns true if the current window is focused based on the given flags + pub fn is_window_focused_with_flags(&self, flags: WindowFocusedFlags) -> bool { + unsafe { sys::igIsWindowFocused(flags.bits() as i32) } + } + /// Returns true if the current window is hovered + pub fn is_window_hovered(&self) -> bool { + unsafe { sys::igIsWindowHovered(0) } + } + /// Returns true if the current window is hovered based on the given flags + pub fn is_window_hovered_with_flags(&self, flags: WindowHoveredFlags) -> bool { + unsafe { sys::igIsWindowHovered(flags.bits() as i32) } + } + /// Returns the position of the current window (in screen space) + pub fn window_pos(&self) -> [f32; 2] { + unsafe { sys::igGetWindowPos_nonUDT2().into() } + } + /// Returns the size of the current window + pub fn window_size(&self) -> [f32; 2] { + unsafe { sys::igGetWindowSize_nonUDT2().into() } + } +} + +/// Builder for a window +#[must_use] +pub struct Window<'a> { + name: &'a ImStr, + opened: Option<&'a mut bool>, + flags: WindowFlags, + pos: [f32; 2], + pos_cond: Condition, + pos_pivot: [f32; 2], + size: [f32; 2], + size_cond: Condition, + size_constraints: Option<([f32; 2], [f32; 2])>, + content_size: [f32; 2], + collapsed: bool, + collapsed_cond: Condition, + focused: bool, + bg_alpha: f32, +} + +impl<'a> Window<'a> { + /// Creates a new window builder with the given name + pub fn new(name: &ImStr) -> Window { + Window { + name, + opened: None, + flags: WindowFlags::empty(), + pos: [0.0, 0.0], + pos_cond: Condition::Never, + pos_pivot: [0.0, 0.0], + size: [0.0, 0.0], + size_cond: Condition::Never, + size_constraints: None, + content_size: [0.0, 0.0], + collapsed: false, + collapsed_cond: Condition::Never, + focused: false, + bg_alpha: f32::NAN, + } + } + /// Enables the window close button, which sets the passed boolean to false when clicked + #[inline] + pub fn opened(mut self, opened: &'a mut bool) -> Self { + self.opened = Some(opened); + self + } + /// Replace current window flags with the given value + #[inline] + pub fn flags(mut self, flags: WindowFlags) -> Self { + self.flags = flags; + self + } + /// Sets the window position, which is applied based on the given condition value + #[inline] + pub fn position(mut self, position: [f32; 2], condition: Condition) -> Self { + self.pos = position; + self.pos_cond = condition; + self + } + /// Sets the window position pivot, which can be used to adjust the alignment of the window + /// relative to the position. + /// + /// For example, pass [0.5, 0.5] to center the window on the position. + /// Does nothing if window position is not also set with `position()`. + #[inline] + pub fn position_pivot(mut self, pivot: [f32; 2]) -> Self { + self.pos_pivot = pivot; + self + } + /// Sets the window size, which is applied based on the given condition value + #[inline] + pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self { + self.size = size; + self.size_cond = condition; + self + } + /// Sets window size constraints. + /// + /// Use -1.0, -1.0 on either X or Y axis to preserve current size. + #[inline] + pub fn size_constraints(mut self, size_min: [f32; 2], size_max: [f32; 2]) -> Self { + self.size_constraints = Some((size_min, size_max)); + self + } + /// Sets the window content size, which can be used to enforce scrollbars. + /// + /// Does not include window decorations (title bar, menu bar, etc.). Set one of the values to + /// 0.0 to leave the size automatic. + #[inline] + pub fn content_size(mut self, size: [f32; 2]) -> Self { + self.content_size = size; + self + } + /// Sets the window collapse state, which is applied based on the given condition value + #[inline] + pub fn collapsed(mut self, collapsed: bool, condition: Condition) -> Self { + self.collapsed = collapsed; + self.collapsed_cond = condition; + self + } + /// Sets the window focused state, which can be used to bring the window to front + #[inline] + pub fn focused(mut self, focused: bool) -> Self { + self.focused = focused; + self + } + /// Sets the background color alpha value. + /// + /// See also `draw_background` + #[inline] + pub fn bg_alpha(mut self, bg_alpha: f32) -> Self { + self.bg_alpha = bg_alpha; + self + } + /// Enables/disables the title bar. + /// + /// Enabled by default. + #[inline] + pub fn title_bar(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_TITLE_BAR, !value); + self + } + /// Enables/disables resizing with the lower-right grip. + /// + /// Enabled by default. + #[inline] + pub fn resizable(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_RESIZE, !value); + self + } + /// Enables/disables moving the window. + /// + /// Enabled by default. + #[inline] + pub fn movable(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_MOVE, !value); + self + } + /// Enables/disables scrollbars (scrolling is still possible with the mouse or + /// programmatically). + /// + /// Enabled by default. + #[inline] + pub fn scroll_bar(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_SCROLLBAR, !value); + self + } + /// Enables/disables vertical scrolling with the mouse wheel. + /// + /// Enabled by default. + /// When enabled, child windows forward the mouse wheel to the parent unless `NO_SCROLLBAR` + /// is also set. + #[inline] + pub fn scrollable(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value); + self + } + /// Enables/disables collapsing the window by double-clicking it. + /// + /// Enabled by default. + #[inline] + pub fn collapsible(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_COLLAPSE, !value); + self + } + /// Enables/disables resizing the window to its content on every frame. + /// + /// Disabled by default. + #[inline] + pub fn always_auto_resize(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value); + self + } + /// Enables/disables drawing of background color and outside border. + /// + /// Enabled by default. + #[inline] + pub fn draw_background(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_BACKGROUND, !value); + self + } + /// Enables/disables loading and saving of settings (e.g. from/to an .ini file). + /// + /// Enabled by default. + #[inline] + pub fn save_settings(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value); + self + } + /// Enables/disables catching mouse input. + /// + /// Enabled by default. + /// Note: Hovering test will pass through when disabled + #[inline] + pub fn mouse_inputs(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_MOUSE_INPUTS, !value); + self + } + /// Enables/disables the menu bar. + /// + /// Disabled by default. + #[inline] + pub fn menu_bar(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::MENU_BAR, value); + self + } + /// Enables/disables the horizontal scrollbar. + /// + /// Disabled by default. + #[inline] + pub fn horizontal_scrollbar(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value); + self + } + /// Enables/disables taking focus when transitioning from hidden to visible state. + /// + /// Enabled by default. + #[inline] + pub fn focus_on_appearing(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value); + self + } + /// Enables/disables bringing the window to front when taking focus (e.g. clicking it or + /// programmatically giving it focus). + /// + /// Enabled by default. + #[inline] + pub fn bring_to_front_on_focus(mut self, value: bool) -> Self { + self.flags + .set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value); + self + } + /// When enabled, forces the vertical scrollbar to render regardless of the content size. + /// + /// Disabled by default. + #[inline] + pub fn always_vertical_scrollbar(mut self, value: bool) -> Self { + self.flags + .set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value); + self + } + /// When enabled, forces the horizontal scrollbar to render regardless of the content size. + /// + /// Disabled by default. + #[inline] + pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self { + self.flags + .set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value); + self + } + /// When enabled, ensures child windows without border use `style.window_padding`. + /// + /// Disabled by default. + #[inline] + pub fn always_use_window_padding(mut self, value: bool) -> Self { + self.flags + .set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value); + self + } + /// Enables/disables gamepad/keyboard navigation within the window. + /// + /// Enabled by default. + #[inline] + pub fn nav_inputs(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_NAV_INPUTS, !value); + self + } + /// Enables/disables focusing toward this window with gamepad/keyboard navigation (e.g. + /// CTRL+TAB). + /// + /// Enabled by default. + #[inline] + pub fn nav_focus(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::NO_NAV_FOCUS, !value); + self + } + /// When enabled, appends '*' to title without affecting the ID, as a convenience. + /// + /// Disabled by default. + #[inline] + pub fn unsaved_document(mut self, value: bool) -> Self { + self.flags.set(WindowFlags::UNSAVED_DOCUMENT, value); + self + } + /// Disable gamepad/keyboard navigation and focusing. + /// + /// Shorthand for + /// ```text + /// .nav_inputs(false) + /// .nav_focus(false) + /// ``` + #[inline] + pub fn no_nav(mut self) -> Self { + self.flags |= WindowFlags::NO_NAV; + self + } + /// Disable all window decorations. + /// + /// Shorthand for + /// ```text + /// .title_bar(false) + /// .resizable(false) + /// .scroll_bar(false) + /// .collapsible(false) + /// ``` + #[inline] + pub fn no_decoration(mut self) -> Self { + self.flags |= WindowFlags::NO_DECORATION; + self + } + /// Don't handle input. + /// + /// Shorthand for + /// ```text + /// .mouse_inputs(false) + /// .nav_inputs(false) + /// .nav_focus(false) + /// ``` + #[inline] + pub fn no_inputs(mut self) -> Self { + self.flags |= WindowFlags::NO_INPUTS; + self + } + /// Builds this window, pushes it to the window stack, and starts appending to it + pub fn begin<'ui>(self, _: &'ui Ui<'ui>) -> WindowToken<'ui> { + if self.pos_cond != Condition::Never { + unsafe { + sys::igSetNextWindowPos( + self.pos.into(), + self.pos_cond as i32, + self.pos_pivot.into(), + ) + }; + } + if self.size_cond != Condition::Never { + unsafe { sys::igSetNextWindowSize(self.size.into(), self.size_cond as i32) }; + } + if let Some((size_min, size_max)) = self.size_constraints { + // TODO: callback support + unsafe { + sys::igSetNextWindowSizeConstraints( + size_min.into(), + size_max.into(), + None, + ptr::null_mut(), + ) + }; + } + if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 { + unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) }; + } + if self.collapsed_cond != Condition::Never { + unsafe { sys::igSetNextWindowCollapsed(self.collapsed, self.collapsed_cond as i32) }; + } + if self.focused { + unsafe { sys::igSetNextWindowFocus() }; + } + if self.bg_alpha.is_finite() { + unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) }; + } + let should_render = unsafe { + sys::igBegin( + self.name.as_ptr(), + self.opened + .map(|x| x as *mut bool) + .unwrap_or(ptr::null_mut()), + self.flags.bits() as i32, + ) + }; + WindowToken { + should_render, + should_end: true, + _ui: PhantomData, + } + } + /// Builds this window using the given closure to create the window content. + /// + /// Note: the closure is not called if no window content is visible (e.g. window is collapsed + /// or fully clipped). + pub fn build(self, ui: &Ui, f: F) { + let window = self.begin(ui); + if window.should_render { + f(); + } + window.end(); + } +} + +/// Represents a window pushed to the window stack +pub struct WindowToken<'ui> { + /// True, if the window contents should be rendered + pub should_render: bool, + should_end: bool, + _ui: PhantomData<&'ui Ui<'ui>>, +} + +impl<'ui> WindowToken<'ui> { + /// Finishes the current window and pops it from the window stack + pub fn end(mut self) { + self.should_end = false; + unsafe { sys::igEnd() }; + } +} + +impl<'ui> Drop for WindowToken<'ui> { + fn drop(&mut self) { + if self.should_end { + unsafe { sys::igEnd() }; + } + } +}