diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index c89367b..9ac6d8e 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -6,6 +6,10 @@ - BREAKING: Removed `push_style_colors` and `push_style_vars`. Instead, use `push_style_color` in a loop. This was deprecated in `0.7.0` and should have been removed in `0.8.0`. This also removes their associated tokens. +- BREAKING: Ui now does not have a lifetime associated with it, but is only ever given to users in the form of `&mut Ui`. Additionally, the `render` function has been moved to the `Context` instead of `Ui`. + +- BREAKING: `SharedFontAtlas` now uses `UnsafeCell` rather than `Rc` as its wrapper -- this simplifies the codebase and more accurately reflects how we expect `SharedFontAtlas` to be used (ie, you're probably going to set it up once, and then give it around, rather than constantly edit it). `SharedFontAtlas` users, if this change is very bad for you, please let us know with issues! + ## [0.8.0] - 2021-09-17 Welcome to the `0.8.0` update. This is one of the largest updates imgui-rs has ever seen; it will generate errors in a `0.7` project, but hopefully it should be both quick to fix, and enjoyable to update. See our [release page](https://github.com/imgui-rs/imgui-rs/releases/tag/v0.8.0) for more information and a list of contributors to this cycle. Thank you to everyone who uses `imgui-rs`, files issues, and spend their time and effort to PR new changes into the codebase. Because of all that effort, this is by far the best `imgui-rs` has looked! diff --git a/imgui-examples/examples/support/mod.rs b/imgui-examples/examples/support/mod.rs index 2a5c9d5..aea615a 100644 --- a/imgui-examples/examples/support/mod.rs +++ b/imgui-examples/examples/support/mod.rs @@ -120,8 +120,8 @@ impl System { let gl_window = display.gl_window(); let mut target = display.draw(); target.clear_color_srgb(1.0, 1.0, 1.0, 1.0); - platform.prepare_render(&ui, gl_window.window()); - let draw_data = ui.render(); + platform.prepare_render(ui, gl_window.window()); + let draw_data = imgui.render(); renderer .render(&mut target, draw_data) .expect("Rendering failed"); diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index a43e95b..f62eaa0 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -330,7 +330,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { window = window.opened(opened) } window.build(|| { - ui.push_item_width(-140.0); + let _w = ui.push_item_width(-140.0); ui.text(format!("dear imgui says hello. ({})", imgui::dear_imgui_version())); if let Some(menu_bar) = ui.begin_menu_bar() { if let Some(menu) = ui.begin_menu("Menu") { @@ -827,7 +827,7 @@ CTRL+click on individual component to input value.\n", }); } -fn show_example_app_main_menu_bar<'a>(ui: &Ui<'a>, state: &mut State) { +fn show_example_app_main_menu_bar(ui: &Ui, state: &mut State) { if let Some(menu_bar) = ui.begin_main_menu_bar() { if let Some(menu) = ui.begin_menu("File") { show_example_menu_file(ui, &mut state.file_menu); @@ -849,7 +849,7 @@ fn show_example_app_main_menu_bar<'a>(ui: &Ui<'a>, state: &mut State) { } } -fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) { +fn show_example_menu_file(ui: &Ui, state: &mut FileMenuState) { MenuItem::new("(dummy menu)").enabled(false).build(ui); MenuItem::new("New").build(ui); MenuItem::new("Open").shortcut("Ctrl+O").build(ui); diff --git a/imgui-glium-renderer/src/lib.rs b/imgui-glium-renderer/src/lib.rs index 723fae9..eddc659 100644 --- a/imgui-glium-renderer/src/lib.rs +++ b/imgui-glium-renderer/src/lib.rs @@ -276,7 +276,7 @@ impl Renderer { } fn upload_font_texture( - mut fonts: imgui::FontAtlasRefMut, + fonts: &mut imgui::FontAtlas, ctx: &Rc, ) -> Result { let texture = fonts.build_rgba32_texture(); diff --git a/imgui-glow-renderer/examples/01_basic.rs b/imgui-glow-renderer/examples/01_basic.rs index 0ca9091..ffdd4c6 100644 --- a/imgui-glow-renderer/examples/01_basic.rs +++ b/imgui-glow-renderer/examples/01_basic.rs @@ -51,8 +51,8 @@ fn main() { let ui = imgui_context.frame(); ui.show_demo_window(&mut true); - winit_platform.prepare_render(&ui, window.window()); - let draw_data = ui.render(); + winit_platform.prepare_render(ui, window.window()); + let draw_data = imgui_context.render(); // This is the only extra render step to add ig_renderer diff --git a/imgui-glow-renderer/examples/02_triangle.rs b/imgui-glow-renderer/examples/02_triangle.rs index 55a2b4a..f1c1e98 100644 --- a/imgui-glow-renderer/examples/02_triangle.rs +++ b/imgui-glow-renderer/examples/02_triangle.rs @@ -41,8 +41,8 @@ fn main() { let ui = imgui_context.frame(); ui.show_demo_window(&mut true); - winit_platform.prepare_render(&ui, window.window()); - let draw_data = ui.render(); + winit_platform.prepare_render(ui, window.window()); + let draw_data = imgui_context.render(); // Render imgui on top of it ig_renderer diff --git a/imgui-glow-renderer/examples/03_triangle_gles.rs b/imgui-glow-renderer/examples/03_triangle_gles.rs index 989a788..b20d258 100644 --- a/imgui-glow-renderer/examples/03_triangle_gles.rs +++ b/imgui-glow-renderer/examples/03_triangle_gles.rs @@ -55,8 +55,8 @@ fn main() { let ui = imgui_context.frame(); ui.show_demo_window(&mut true); - winit_platform.prepare_render(&ui, window.window()); - let draw_data = ui.render(); + winit_platform.prepare_render(ui, window.window()); + let draw_data = imgui_context.render(); // Render imgui on top ig_renderer diff --git a/imgui-glow-renderer/examples/04_custom_textures.rs b/imgui-glow-renderer/examples/04_custom_textures.rs index 70e4d95..5020386 100644 --- a/imgui-glow-renderer/examples/04_custom_textures.rs +++ b/imgui-glow-renderer/examples/04_custom_textures.rs @@ -56,10 +56,10 @@ fn main() { unsafe { gl.clear(glow::COLOR_BUFFER_BIT) }; let ui = imgui_context.frame(); - textures_ui.show(&ui); + textures_ui.show(ui); - winit_platform.prepare_render(&ui, window.window()); - let draw_data = ui.render(); + winit_platform.prepare_render(ui, window.window()); + let draw_data = imgui_context.render(); ig_renderer .render(&gl, &textures, draw_data) .expect("error rendering imgui"); diff --git a/imgui-glow-renderer/src/lib.rs b/imgui-glow-renderer/src/lib.rs index eacdd90..87fd214 100644 --- a/imgui-glow-renderer/src/lib.rs +++ b/imgui-glow-renderer/src/lib.rs @@ -1042,7 +1042,7 @@ pub type RenderError = String; fn prepare_font_atlas( gl: &Context, - mut fonts: imgui::FontAtlasRefMut, + fonts: &mut imgui::FontAtlas, texture_map: &mut T, ) -> Result { #![allow(clippy::cast_possible_wrap)] diff --git a/imgui/src/clipboard.rs b/imgui/src/clipboard.rs index 38ebc97..f1abb0d 100644 --- a/imgui/src/clipboard.rs +++ b/imgui/src/clipboard.rs @@ -93,7 +93,7 @@ pub(crate) unsafe extern "C" fn set_clipboard_text(user_data: *mut c_void, text: /// # Clipboard #[allow(clippy::fn_address_comparisons)] // This is allowed because although function addresses wont be unique, we just care if its OURS -impl<'ui> Ui<'ui> { +impl Ui { /// Returns the current clipboard contents as text, or None if the clipboard is empty or cannot /// be accessed pub fn clipboard_text(&self) -> Option { diff --git a/imgui/src/columns.rs b/imgui/src/columns.rs index b282e91..ea00f3a 100644 --- a/imgui/src/columns.rs +++ b/imgui/src/columns.rs @@ -2,7 +2,7 @@ use crate::sys; use crate::Ui; /// # Columns -impl<'ui> Ui<'ui> { +impl Ui { #[doc(alias = "Columns")] pub fn columns(&self, count: i32, id: impl AsRef, border: bool) { unsafe { sys::igColumns(count, self.scratch_txt(id), border) } diff --git a/imgui/src/context.rs b/imgui/src/context.rs index 592ed88..19afb28 100644 --- a/imgui/src/context.rs +++ b/imgui/src/context.rs @@ -1,17 +1,16 @@ use parking_lot::ReentrantMutex; -use std::cell::{RefCell, UnsafeCell}; +use std::cell::UnsafeCell; use std::ffi::{CStr, CString}; use std::ops::Drop; use std::path::PathBuf; use std::ptr; -use std::rc::Rc; use crate::clipboard::{ClipboardBackend, ClipboardContext}; -use crate::fonts::atlas::{FontAtlas, FontAtlasRefMut, FontId, SharedFontAtlas}; +use crate::fonts::atlas::{FontAtlas, FontId, SharedFontAtlas}; use crate::io::Io; use crate::style::Style; -use crate::sys; use crate::Ui; +use crate::{sys, DrawData}; /// An imgui-rs context. /// @@ -50,7 +49,7 @@ use crate::Ui; #[derive(Debug)] pub struct Context { raw: *mut sys::ImGuiContext, - shared_font_atlas: Option>>, + shared_font_atlas: Option, ini_filename: Option, log_filename: Option, platform_name: Option, @@ -60,6 +59,8 @@ pub struct Context { // we also put it in an unsafecell since we're going to give // imgui a mutable pointer to it. clipboard_ctx: Box>, + + ui: Ui, } // This mutex needs to be used to guard all public functions that can affect the underlying @@ -92,7 +93,7 @@ impl Context { /// /// Panics if an active context already exists #[doc(alias = "CreateContext")] - pub fn create_with_shared_font_atlas(shared_font_atlas: Rc>) -> Self { + pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Self { Self::create_internal(Some(shared_font_atlas)) } /// Suspends this context so another context can be the active context. @@ -215,18 +216,15 @@ impl Context { io.clipboard_user_data = clipboard_ctx.get() as *mut _; self.clipboard_ctx = clipboard_ctx; } - fn create_internal(shared_font_atlas: Option>>) -> Self { + fn create_internal(mut shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); assert!( no_current_context(), "A new active context cannot be created, because another one already exists" ); - let shared_font_atlas_ptr = match &shared_font_atlas { - Some(shared_font_atlas) => { - let borrowed_font_atlas = shared_font_atlas.borrow(); - borrowed_font_atlas.0 - } + let shared_font_atlas_ptr = match &mut shared_font_atlas { + Some(shared_font_atlas) => shared_font_atlas.as_ptr_mut(), None => ptr::null_mut(), }; // Dear ImGui implicitly sets the current context during igCreateContext if the current @@ -241,6 +239,9 @@ impl Context { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), + ui: Ui { + buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), + }, } } fn is_current_context(&self) -> bool { @@ -256,6 +257,10 @@ impl Drop for Context { // If this context is the active context, Dear ImGui automatically deactivates it during // destruction unsafe { + // end the frame if necessary... + if !sys::igGetCurrentContext().is_null() && sys::igGetFrameCount() > 0 { + sys::igEndFrame(); + } sys::igDestroyContext(self.raw); } } @@ -289,8 +294,9 @@ impl SuspendedContext { pub fn create() -> Self { Self::create_internal(None) } + /// Creates a new suspended imgui-rs context with a shared font atlas. - pub fn create_with_shared_font_atlas(shared_font_atlas: Rc>) -> Self { + pub fn create_with_shared_font_atlas(shared_font_atlas: SharedFontAtlas) -> Self { Self::create_internal(Some(shared_font_atlas)) } /// Attempts to activate this suspended context. @@ -311,7 +317,7 @@ impl SuspendedContext { Err(self) } } - fn create_internal(shared_font_atlas: Option>>) -> Self { + fn create_internal(shared_font_atlas: Option) -> Self { let _guard = CTX_MUTEX.lock(); let raw = unsafe { sys::igCreateContext(ptr::null_mut()) }; let ctx = Context { @@ -322,6 +328,9 @@ impl SuspendedContext { platform_name: None, renderer_name: None, clipboard_ctx: Box::new(ClipboardContext::dummy().into()), + ui: Ui { + buffer: UnsafeCell::new(crate::string::UiBuffer::new(1024)), + }, }; if ctx.is_current_context() { // Oops, the context was activated -> deactivate @@ -403,7 +412,7 @@ fn test_suspend_failure() { #[test] fn test_shared_font_atlas() { let _guard = crate::test::TEST_MUTEX.lock(); - let atlas = Rc::new(RefCell::new(SharedFontAtlas::create())); + let atlas = SharedFontAtlas::create(); let suspended1 = SuspendedContext::create_with_shared_font_atlas(atlas.clone()); let mut ctx2 = Context::create_with_shared_font_atlas(atlas); { @@ -414,17 +423,6 @@ fn test_shared_font_atlas() { let _borrow = ctx.fonts(); } -#[test] -#[should_panic] -fn test_shared_font_atlas_borrow_panic() { - let _guard = crate::test::TEST_MUTEX.lock(); - let atlas = Rc::new(RefCell::new(SharedFontAtlas::create())); - let _suspended = SuspendedContext::create_with_shared_font_atlas(atlas.clone()); - let mut ctx = Context::create_with_shared_font_atlas(atlas.clone()); - let _borrow1 = atlas.borrow(); - let _borrow2 = ctx.fonts(); -} - #[test] fn test_ini_load_save() { let (_guard, mut ctx) = crate::test::test_ctx(); @@ -498,45 +496,51 @@ impl Context { } } /// Returns a mutable reference to the font atlas. - /// - /// # Panics - /// - /// Panics if the context uses a shared font atlas that is already borrowed - pub fn fonts(&mut self) -> FontAtlasRefMut<'_> { - match self.shared_font_atlas { - Some(ref font_atlas) => FontAtlasRefMut::Shared(font_atlas.borrow_mut()), - None => unsafe { - // safe because FontAtlas is a transparent wrapper around sys::ImFontAtlas - let fonts = &mut *(self.io_mut().fonts as *mut FontAtlas); - FontAtlasRefMut::Owned(fonts) - }, - } + pub fn fonts(&mut self) -> &mut FontAtlas { + // we take this with an `&mut Self` here, which means + // that we can't get the sharedfontatlas through safe code + // otherwise + unsafe { &mut *(self.io_mut().fonts as *mut FontAtlas) } } + + /// Attempts to clone the interior shared font atlas **if it exists**. + pub fn clone_shared_font_atlas(&mut self) -> Option { + self.shared_font_atlas.clone() + } + + /// Starts a new frame. Use [`new_frame`] instead. + /// + /// [`new_frame`]: Self::new_frame + pub fn frame(&mut self) -> &mut Ui { + self.new_frame() + } + /// Starts a new frame and returns an `Ui` instance for constructing a user interface. - /// - /// # Panics - /// - /// Panics if the context uses a shared font atlas that is already borrowed #[doc(alias = "NewFame")] - pub fn frame(&mut self) -> Ui<'_> { + pub fn new_frame(&mut self) -> &mut Ui { // Clear default font if it no longer exists. This could be an error in the future let default_font = self.io().font_default; if !default_font.is_null() && self.fonts().get_font(FontId(default_font)).is_none() { self.io_mut().font_default = ptr::null_mut(); } - // NewFrame/Render/EndFrame mutate the font atlas so we need exclusive access to it - let font_atlas = self - .shared_font_atlas - .as_ref() - .map(|font_atlas| font_atlas.borrow_mut()); // TODO: precondition checks unsafe { sys::igNewFrame(); } - Ui { - ctx: self, - font_atlas, - buffer: crate::UiBuffer::new(1024).into(), + + &mut self.ui + } + + /// Renders the frame and returns a reference to the resulting draw data. + /// + /// This should only be called after calling [`new_frame`]. + /// + /// [`new_frame`]: Self::new_frame + #[doc(alias = "Render", alias = "GetDrawData")] + pub fn render(&mut self) -> &DrawData { + unsafe { + sys::igRender(); + &*(sys::igGetDrawData() as *mut DrawData) } } } diff --git a/imgui/src/drag_drop.rs b/imgui/src/drag_drop.rs index 2fbf0b5..1f209a5 100644 --- a/imgui/src/drag_drop.rs +++ b/imgui/src/drag_drop.rs @@ -74,7 +74,7 @@ bitflags!( /// /// ```no_run /// # use imgui::*; -/// fn show_ui(ui: &Ui<'_>) { +/// fn show_ui(ui: &Ui) { /// ui.button("Hello, I am a drag source!"); /// /// // Creates an empty DragSource with no tooltip @@ -141,7 +141,7 @@ impl> DragDropSource { /// /// ```no_run /// # use imgui::*; - /// fn show_ui(ui: &Ui<'_>, drop_message: &mut Option) { + /// fn show_ui(ui: &Ui, drop_message: &mut Option) { /// ui.button("Drag me!"); /// /// let drag_drop_name = "Test Drag"; @@ -175,7 +175,7 @@ impl> DragDropSource { /// If you want to pass a simple integer or other "plain old data", take a look at /// [begin_payload](Self::begin_payload). #[inline] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin<'ui>(self, ui: &Ui) -> Option> { self.begin_payload(ui, ()) } @@ -194,7 +194,7 @@ impl> DragDropSource { /// /// ```no_run /// # use imgui::*; - /// fn show_ui(ui: &Ui<'_>) { + /// fn show_ui(ui: &Ui) { /// ui.button("Drag me!"); /// /// let drag_drop_name = "Test Drag"; @@ -224,7 +224,7 @@ impl> DragDropSource { #[inline] pub fn begin_payload<'ui, P: Copy + 'static>( self, - ui: &Ui<'ui>, + ui: &Ui, payload: P, ) -> Option> { unsafe { @@ -266,7 +266,7 @@ impl> DragDropSource { #[inline] pub unsafe fn begin_payload_unchecked<'ui>( &self, - ui: &Ui<'ui>, + ui: &Ui, ptr: *const ffi::c_void, size: usize, ) -> Option> { @@ -283,7 +283,7 @@ impl> DragDropSource { } /// A helper struct for RAII drap-drop support. -pub struct DragDropSourceToolTip<'ui>(PhantomData>); +pub struct DragDropSourceToolTip<'ui>(PhantomData<&'ui Ui>); impl DragDropSourceToolTip<'_> { /// Creates a new tooltip internally. @@ -310,7 +310,7 @@ impl Drop for DragDropSourceToolTip<'_> { /// /// ```no_run /// # use imgui::*; -/// fn show_ui(ui: &Ui<'_>) { +/// fn show_ui(ui: &Ui) { /// // Drop something on this button please! /// ui.button("Hello, I am a drag Target!"); /// @@ -339,14 +339,14 @@ impl Drop for DragDropSourceToolTip<'_> { /// on this struct. Each of these methods will spit out a _Payload struct with an increasing /// amount of information on the Payload. The absolute safest solution is [accept_payload_empty](Self::accept_payload_empty). #[derive(Debug)] -pub struct DragDropTarget<'ui>(&'ui Ui<'ui>); +pub struct DragDropTarget<'ui>(&'ui Ui); impl<'ui> DragDropTarget<'ui> { /// Creates a new DragDropTarget, holding the [Ui]'s lifetime for the duration /// of its existence. This is required since this struct runs some code on its Drop /// to end the DragDropTarget code. #[doc(alias = "BeginDragDropTarget")] - pub fn new(ui: &'ui Ui<'ui>) -> Option { + pub fn new(ui: &'ui Ui) -> Option { let should_begin = unsafe { sys::igBeginDragDropTarget() }; if should_begin { Some(Self(ui)) diff --git a/imgui/src/draw_list.rs b/imgui/src/draw_list.rs index 27323b0..d58ef6d 100644 --- a/imgui/src/draw_list.rs +++ b/imgui/src/draw_list.rs @@ -75,7 +75,7 @@ enum DrawListType { pub struct DrawListMut<'ui> { draw_list_type: DrawListType, draw_list: *mut ImDrawList, - _phantom: PhantomData<&'ui Ui<'ui>>, + _phantom: PhantomData<&'ui Ui>, } // Lock for each variant of draw list. See https://github.com/imgui-rs/imgui-rs/issues/488 @@ -124,7 +124,7 @@ impl<'ui> DrawListMut<'ui> { } #[doc(alias = "GetWindowDrawList")] - pub(crate) fn window(_: &Ui<'ui>) -> Self { + pub(crate) fn window(_: &Ui) -> Self { Self::lock_draw_list(DrawListType::Window); Self { @@ -135,7 +135,7 @@ impl<'ui> DrawListMut<'ui> { } #[doc(alias = "GetBackgroundDrawList")] - pub(crate) fn background(_: &Ui<'ui>) -> Self { + pub(crate) fn background(_: &Ui) -> Self { Self::lock_draw_list(DrawListType::Background); Self { draw_list: unsafe { sys::igGetBackgroundDrawList() }, @@ -145,7 +145,7 @@ impl<'ui> DrawListMut<'ui> { } #[doc(alias = "GetForegroundDrawList")] - pub(crate) fn foreground(_: &Ui<'ui>) -> Self { + pub(crate) fn foreground(_: &Ui) -> Self { Self::lock_draw_list(DrawListType::Foreground); Self { draw_list: unsafe { sys::igGetForegroundDrawList() }, diff --git a/imgui/src/fonts/atlas.rs b/imgui/src/fonts/atlas.rs index 708b494..a3f438b 100644 --- a/imgui/src/fonts/atlas.rs +++ b/imgui/src/fonts/atlas.rs @@ -1,9 +1,8 @@ use bitflags::bitflags; -use std::cell; use std::f32; -use std::ops::{Deref, DerefMut}; use std::os::raw::{c_int, c_uchar, c_void}; use std::ptr; +use std::rc::Rc; use std::slice; use crate::fonts::font::Font; @@ -433,76 +432,95 @@ pub struct FontAtlasTexture<'a> { } /// A font atlas that can be shared between contexts -#[derive(Debug)] -pub struct SharedFontAtlas(pub(crate) *mut sys::ImFontAtlas); +#[derive(Debug, Clone)] +pub struct SharedFontAtlas(pub(crate) Rc<*mut sys::ImFontAtlas>); + +impl std::ops::Deref for SharedFontAtlas { + type Target = Rc<*mut sys::ImFontAtlas>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for SharedFontAtlas { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} impl SharedFontAtlas { #[doc(alias = "ImFontAtlas", alias = "ImFontAtlas::ImFontAtlas")] pub fn create() -> SharedFontAtlas { - SharedFontAtlas(unsafe { sys::ImFontAtlas_ImFontAtlas() }) + SharedFontAtlas(unsafe { Rc::new(sys::ImFontAtlas_ImFontAtlas()) }) + } + + /// Gets a raw pointer to the underlying `ImFontAtlas`. + pub fn as_ptr(&self) -> *const sys::ImFontAtlas { + *self.0 as *const _ + } + + /// Gets a raw pointer to the underlying `ImFontAtlas`. + pub fn as_ptr_mut(&mut self) -> *mut sys::ImFontAtlas { + *self.0 } } impl Drop for SharedFontAtlas { #[doc(alias = "ImFontAtlas::Destory")] fn drop(&mut self) { - unsafe { sys::ImFontAtlas_destroy(self.0) }; - } -} - -impl Deref for SharedFontAtlas { - type Target = FontAtlas; - fn deref(&self) -> &FontAtlas { - unsafe { &*(self.0 as *const FontAtlas) } - } -} - -impl DerefMut for SharedFontAtlas { - fn deref_mut(&mut self) -> &mut FontAtlas { - unsafe { &mut *(self.0 as *mut FontAtlas) } - } -} - -/// An immutably borrowed reference to a (possibly shared) font atlas -pub enum FontAtlasRef<'a> { - Owned(&'a FontAtlas), - Shared(&'a cell::RefMut<'a, SharedFontAtlas>), -} - -impl<'a> Deref for FontAtlasRef<'a> { - type Target = FontAtlas; - fn deref(&self) -> &FontAtlas { - use self::FontAtlasRef::*; - match self { - Owned(atlas) => atlas, - Shared(cell) => cell, + // if we're about to drop the last one... + if Rc::strong_count(&self.0) == 1 { + unsafe { sys::ImFontAtlas_destroy(*self.0) }; } } } -/// A mutably borrowed reference to a (possibly shared) font atlas -pub enum FontAtlasRefMut<'a> { - Owned(&'a mut FontAtlas), - Shared(cell::RefMut<'a, SharedFontAtlas>), -} +// /// An immutably borrowed reference to a (possibly shared) font atlas +// pub enum FontAtlasRef<'a> { +// Owned(&'a FontAtlas), +// Shared(&'a cell::RefMut<'a, SharedFontAtlas>), +// } -impl<'a> Deref for FontAtlasRefMut<'a> { - type Target = FontAtlas; - fn deref(&self) -> &FontAtlas { - use self::FontAtlasRefMut::*; - match self { - Owned(atlas) => atlas, - Shared(cell) => cell, - } - } -} +// impl<'a> Deref for FontAtlasRef<'a> { +// type Target = FontAtlas; +// fn deref(&self) -> &FontAtlas { +// use self::FontAtlasRef::*; +// match self { +// Owned(atlas) => atlas, +// Shared(cell) => { +// let font_atlas: &SharedFontAtlas = &cell; +// let font_atlas: &FontAtlas = &font_atlas; -impl<'a> DerefMut for FontAtlasRefMut<'a> { - fn deref_mut(&mut self) -> &mut FontAtlas { - use self::FontAtlasRefMut::*; - match self { - Owned(atlas) => atlas, - Shared(cell) => cell, - } - } -} +// todo!() +// } +// } +// } +// } + +// /// A mutably borrowed reference to a (possibly shared) font atlas +// pub enum FontAtlasRefMut<'a> { +// Owned(&'a mut FontAtlas), +// Shared(cell::RefMut<'a, SharedFontAtlas>), +// } + +// impl<'a> Deref for FontAtlasRefMut<'a> { +// type Target = FontAtlas; +// fn deref(&self) -> &FontAtlas { +// use self::FontAtlasRefMut::*; +// match self { +// Owned(atlas) => atlas, +// Shared(cell) => cell, +// } +// } +// } + +// impl<'a> DerefMut for FontAtlasRefMut<'a> { +// fn deref_mut(&mut self) -> &mut FontAtlas { +// use self::FontAtlasRefMut::*; +// match self { +// Owned(atlas) => atlas, +// Shared(cell) => cell, +// } +// } +// } diff --git a/imgui/src/fonts/mod.rs b/imgui/src/fonts/mod.rs index 3f69efe..f1034a5 100644 --- a/imgui/src/fonts/mod.rs +++ b/imgui/src/fonts/mod.rs @@ -8,7 +8,7 @@ pub mod glyph; pub mod glyph_ranges; /// # Fonts -impl<'ui> Ui<'ui> { +impl Ui { /// Returns the current font #[doc(alias = "GetFont")] pub fn current_font(&self) -> &Font { diff --git a/imgui/src/input/keyboard.rs b/imgui/src/input/keyboard.rs index bab12f4..b425d9c 100644 --- a/imgui/src/input/keyboard.rs +++ b/imgui/src/input/keyboard.rs @@ -91,7 +91,7 @@ impl FocusedWidget { } /// # Input: Keyboard -impl<'ui> Ui<'ui> { +impl Ui { /// Returns the key index of the given key identifier. /// /// Equivalent to indexing the Io struct `key_map` field: `ui.io().key_map[key]` diff --git a/imgui/src/input/mouse.rs b/imgui/src/input/mouse.rs index 7aa66ab..7664455 100644 --- a/imgui/src/input/mouse.rs +++ b/imgui/src/input/mouse.rs @@ -89,7 +89,7 @@ fn test_mouse_cursor_variants() { } /// # Input: Mouse -impl<'ui> Ui<'ui> { +impl Ui { /// Returns true if the given mouse button is held down. /// /// Equivalent to indexing the Io struct with the button, e.g. `ui.io()[button]`. @@ -237,41 +237,46 @@ fn test_mouse_down_clicked_released() { let (_guard, mut ctx) = crate::test::test_ctx_initialized(); { ctx.io_mut().mouse_down = [false; 5]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_down(button)); assert!(!ui.is_any_mouse_down()); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_released(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_down(button)); assert!(ui.is_any_mouse_down()); assert!(ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_released(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_down(button)); assert!(ui.is_any_mouse_down()); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_released(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = false; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_down(button)); assert!(!ui.is_any_mouse_down()); assert!(!ui.is_mouse_clicked(button)); assert!(ui.is_mouse_released(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_down(button)); assert!(!ui.is_any_mouse_down()); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_released(button)); + let _ = ctx.render(); } } } @@ -279,6 +284,7 @@ fn test_mouse_down_clicked_released() { #[test] fn test_mouse_double_click() { let (_guard, mut ctx) = crate::test::test_ctx_initialized(); + // Workaround for dear imgui bug/feature: // If a button is clicked before io.mouse_double_click_time seconds has passed after the // context is initialized, the single click is interpreted as a double-click. This happens @@ -287,44 +293,51 @@ fn test_mouse_double_click() { { // Pass one second of time ctx.io_mut().delta_time = 1.0; - let _ = ctx.frame(); + let _ = ctx.new_frame(); + let _ = ctx.render(); } // Fast clicks ctx.io_mut().delta_time = 1.0 / 60.0; for &button in MouseButton::VARIANTS.iter() { { ctx.io_mut().mouse_down = [false; 5]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = false; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_clicked(button)); assert!(ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } } // Slow clicks @@ -332,37 +345,43 @@ fn test_mouse_double_click() { for &button in MouseButton::VARIANTS.iter() { { ctx.io_mut().mouse_down = [false; 5]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = false; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } { - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_clicked(button)); assert!(!ui.is_mouse_double_clicked(button)); + let _ = ctx.render(); } } } @@ -370,7 +389,7 @@ fn test_mouse_double_click() { #[test] fn test_set_get_mouse_cursor() { let (_guard, mut ctx) = crate::test::test_ctx_initialized(); - let ui = ctx.frame(); + let ui = ctx.new_frame(); ui.set_mouse_cursor(None); assert_eq!(None, ui.mouse_cursor()); ui.set_mouse_cursor(Some(MouseCursor::Hand)); @@ -384,7 +403,7 @@ fn test_mouse_drags() { { ctx.io_mut().mouse_pos = [0.0, 0.0]; ctx.io_mut().mouse_down = [false; 5]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); @@ -392,10 +411,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] ); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); @@ -403,10 +423,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] ); + let _ = ctx.render(); } { ctx.io_mut().mouse_pos = [0.0, 100.0]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 100.0]); @@ -414,10 +435,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] ); + let _ = ctx.render(); } { ctx.io_mut().mouse_pos = [0.0, 200.0]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 200.0]); @@ -425,11 +447,12 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 200.0] ); + let _ = ctx.render(); } { ctx.io_mut().mouse_pos = [10.0, 10.0]; ctx.io_mut()[button] = false; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [10.0, 10.0]); @@ -437,10 +460,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [10.0, 10.0] ); + let _ = ctx.render(); } { ctx.io_mut()[button] = true; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); @@ -448,10 +472,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] ); + let _ = ctx.render(); } { ctx.io_mut().mouse_pos = [180.0, 180.0]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [170.0, 170.0]); @@ -467,10 +492,11 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] ); + let _ = ctx.render(); } { ctx.io_mut().mouse_pos = [200.0, 200.0]; - let ui = ctx.frame(); + let ui = ctx.new_frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); assert_eq!(ui.mouse_drag_delta_with_button(button), [20.0, 20.0]); @@ -478,6 +504,7 @@ fn test_mouse_drags() { ui.mouse_drag_delta_with_threshold(button, 200.0), [20.0, 20.0] ); + let _ = ctx.render(); } } } diff --git a/imgui/src/input_widget.rs b/imgui/src/input_widget.rs index 200df0f..6e3f073 100644 --- a/imgui/src/input_widget.rs +++ b/imgui/src/input_widget.rs @@ -166,7 +166,7 @@ pub struct InputText<'ui, 'p, L, H = &'static str, T = PassthroughCallback> { buf: &'p mut String, callback_handler: T, flags: InputTextFlags, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L: AsRef> InputText<'ui, 'p, L> { @@ -184,7 +184,7 @@ impl<'ui, 'p, L: AsRef> InputText<'ui, 'p, L> { /// your string. /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. - pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String) -> Self { + pub fn new(ui: &'ui Ui, label: L, buf: &'p mut String) -> Self { InputText { label, hint: None, @@ -343,7 +343,7 @@ pub struct InputTextMultiline<'ui, 'p, L, T = PassthroughCallback> { flags: InputTextFlags, size: [f32; 2], callback_handler: T, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L: AsRef> InputTextMultiline<'ui, 'p, L, PassthroughCallback> { @@ -361,7 +361,7 @@ impl<'ui, 'p, L: AsRef> InputTextMultiline<'ui, 'p, L, PassthroughCallback> /// your string. /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. - pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String, size: impl Into) -> Self { + pub fn new(ui: &'ui Ui, label: L, buf: &'p mut String, size: impl Into) -> Self { InputTextMultiline { label, buf, @@ -482,11 +482,11 @@ pub struct InputInt<'ui, 'p, L> { step: i32, step_fast: i32, flags: InputTextFlags, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L: AsRef> InputInt<'ui, 'p, L> { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut i32) -> Self { + pub fn new(ui: &'ui Ui, label: L, value: &'p mut i32) -> Self { InputInt { label, value, @@ -520,11 +520,11 @@ pub struct InputFloat<'ui, 'p, L> { step: f32, step_fast: f32, flags: InputTextFlags, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L: AsRef> InputFloat<'ui, 'p, L> { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut f32) -> Self { + pub fn new(ui: &'ui Ui, label: L, value: &'p mut f32) -> Self { InputFloat { label, value, @@ -559,7 +559,7 @@ macro_rules! impl_input_floatn { label: L, value: &'p mut T, flags: InputTextFlags, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L, T> $InputFloatN<'ui, 'p, L, T> @@ -568,7 +568,7 @@ macro_rules! impl_input_floatn { T: Copy + Into<$MINT_TARGET>, $MINT_TARGET: Into + Into<[f32; $N]>, { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut T) -> Self { + pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self { $InputFloatN { label, value, @@ -614,7 +614,7 @@ macro_rules! impl_input_intn { label: L, value: &'p mut T, flags: InputTextFlags, - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, L, T> $InputIntN<'ui, 'p, L, T> @@ -623,7 +623,7 @@ macro_rules! impl_input_intn { T: Copy + Into<$MINT_TARGET>, $MINT_TARGET: Into + Into<[i32; $N]>, { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut T) -> Self { + pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self { $InputIntN { label, value, diff --git a/imgui/src/layout.rs b/imgui/src/layout.rs index b0cdd16..b385d91 100644 --- a/imgui/src/layout.rs +++ b/imgui/src/layout.rs @@ -12,7 +12,7 @@ create_token!( ); /// # Cursor / Layout -impl<'ui> Ui<'ui> { +impl Ui { /// Renders a separator (generally horizontal). /// /// This becomes a vertical separator inside a menu bar or in horizontal layout mode. diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 7bfca42..dc126d5 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -4,6 +4,7 @@ pub extern crate imgui_sys as sys; +use std::cell; use std::os::raw::{c_char, c_void}; pub use self::clipboard::*; @@ -115,16 +116,31 @@ impl Context { } } -/// A temporary reference for building the user interface for one frame +/// A reference for building the user interface for one frame #[derive(Debug)] -pub struct Ui<'ui> { - ctx: &'ui Context, - font_atlas: Option>, - // imgui isn't mutli-threaded -- so no one will ever access twice. - buffer: std::cell::UnsafeCell, +pub struct Ui { + /// our scratch sheet + buffer: cell::UnsafeCell, } -impl<'ui> Ui<'ui> { +impl Ui { + /// This provides access to the backing scratch buffer that we use to write + /// strings, along with null-terminators, before we pass normal Rust strs to + /// Dear ImGui. + /// + /// This is given as a get-out-of-jail free card if you need to handle the buffer, + /// or, for example, resize it for some reason. Generally, you should never need this. + /// + /// ## Safety + /// + /// This uses a **static mut** and we assume it will *never* be passed between threads. + /// Do not pass the raw pointer you get between threads at all -- Dear ImGui is single-threaded. + /// We otherwise make no assumptions about the size or keep state in this buffer between calls, + /// so editing the `UiBuffer` is fine. + pub unsafe fn scratch_buffer(&self) -> &cell::UnsafeCell { + &self.buffer + } + /// Internal method to push a single text to our scratch buffer. fn scratch_txt(&self, txt: impl AsRef) -> *const sys::cty::c_char { unsafe { @@ -169,43 +185,44 @@ impl<'ui> Ui<'ui> { unsafe { &*(sys::igGetIO() as *const Io) } } - /// Returns an immutable reference to the font atlas - pub fn fonts(&self) -> FontAtlasRef<'_> { - match self.font_atlas { - Some(ref font_atlas) => FontAtlasRef::Shared(font_atlas), - None => unsafe { - let fonts = &*(self.io().fonts as *const FontAtlas); - FontAtlasRef::Owned(fonts) - }, - } + /// Returns an immutable reference to the font atlas. + pub fn fonts(&self) -> &FontAtlas { + unsafe { &*(self.io().fonts as *const FontAtlas) } } + /// Returns a clone of the user interface style pub fn clone_style(&self) -> Style { - *self.ctx.style() + unsafe { *self.style() } } - /// Renders the frame and returns a reference to the resulting draw data - #[doc(alias = "Render", alias = "GetDrawData")] - pub fn render(self) -> &'ui DrawData { - unsafe { - sys::igRender(); - &*(sys::igGetDrawData() as *mut DrawData) - } - } -} -impl<'a> Drop for Ui<'a> { - #[doc(alias = "EndFrame")] - fn drop(&mut self) { - if !std::thread::panicking() { - unsafe { - sys::igEndFrame(); - } + /// This function, and the library's api, has been changed as of `0.9`! + /// Do not use this function! Instead, use [`Context::render`], + /// which does what this function in `0.8` used to do. + /// + /// This function right now simply **ends** the current frame, but does not + /// return draw data. If you want to end the frame without generated draw data, + /// and thus save some CPU time, use [`end_frame_early`]. + #[deprecated( + since = "0.9.0", + note = "use `Context::render` to render frames, or `end_frame_early` to not render at all" + )] + pub fn render(&mut self) { + self.end_frame_early(); + } + + /// Use this function to end the frame early. + /// After this call, you should **stop using the `Ui` object till `new_frame` has been called.** + /// + /// You probably *don't want this function.* If you want to render your data, use `Context::render` now. + pub fn end_frame_early(&mut self) { + unsafe { + sys::igEndFrame(); } } } /// # Demo, debug, information -impl<'ui> Ui<'ui> { +impl Ui { /// Renders a demo window (previously called a test window), which demonstrates most /// Dear Imgui features. #[doc(alias = "ShowDemoWindow")] @@ -316,7 +333,7 @@ impl<'a> Default for Id<'a> { } } -impl<'ui> Ui<'ui> { +impl Ui { /// # Windows /// Start constructing a window. /// @@ -338,7 +355,7 @@ impl<'ui> Ui<'ui> { /// ui.text("An example"); /// }); /// ``` - pub fn window>(&'ui self, name: Label) -> Window<'ui, '_, Label> { + pub fn window>(&self, name: Label) -> Window<'_, '_, Label> { Window::new(self, name) } @@ -357,13 +374,13 @@ impl<'ui> Ui<'ui> { /// wt.unwrap().end() /// } /// ``` - pub fn child_window>(&'ui self, name: Label) -> ChildWindow<'ui, Label> { + pub fn child_window>(&self, name: Label) -> ChildWindow<'_, Label> { ChildWindow::new(self, name) } } // Widgets: Input -impl<'ui> Ui<'ui> { +impl<'ui> Ui { #[doc(alias = "InputText", alias = "InputTextWithHint")] pub fn input_text<'p, L: AsRef>( &'ui self, @@ -475,7 +492,7 @@ create_token!( ); /// # Tooltips -impl<'ui> Ui<'ui> { +impl Ui { /// Construct a tooltip window that can have any kind of content. /// /// Typically used with `Ui::is_item_hovered()` or some other conditional check. @@ -542,7 +559,7 @@ create_token!( /// imgui can disable widgets so they don't react to mouse/keyboard /// inputs, and are displayed differently (currently dimmed by an /// amount set in [`Style::disabled_alpha`]) -impl<'ui> Ui<'ui> { +impl Ui { /// Creates a scope where interactions are disabled. /// /// Scope ends when returned token is dropped, or `.end()` is @@ -604,7 +621,7 @@ impl<'ui> Ui<'ui> { } // Widgets: ListBox -impl<'ui> Ui<'ui> { +impl Ui { #[doc(alias = "ListBox")] pub fn list_box<'p, StringType: AsRef + ?Sized>( &self, @@ -614,7 +631,7 @@ impl<'ui> Ui<'ui> { height_in_items: i32, ) -> bool { let (label_ptr, items_inner) = unsafe { - let handle = &mut *self.buffer.get(); + let handle = &mut *self.scratch_buffer().get(); handle.refresh_buffer(); let label_ptr = handle.push(label); @@ -671,7 +688,7 @@ impl<'ui> Ui<'ui> { // } } -impl<'ui> Ui<'ui> { +impl<'ui> Ui { #[doc(alias = "PlotLines")] pub fn plot_lines<'p, Label: AsRef>( &'ui self, @@ -680,9 +697,7 @@ impl<'ui> Ui<'ui> { ) -> PlotLines<'ui, 'p, Label> { PlotLines::new(self, label, values) } -} -impl<'ui> Ui<'ui> { #[doc(alias = "PlotHistogram")] pub fn plot_histogram<'p, Label: AsRef>( &'ui self, @@ -691,9 +706,7 @@ impl<'ui> Ui<'ui> { ) -> PlotHistogram<'ui, 'p, Label> { PlotHistogram::new(self, label, values) } -} -impl<'ui> Ui<'ui> { /// Calculate the size required for a given text string. /// /// This is the same as [calc_text_size_with_opts](Self::calc_text_size_with_opts) @@ -736,7 +749,7 @@ impl<'ui> Ui<'ui> { } /// # Draw list for custom drawing -impl<'ui> Ui<'ui> { +impl Ui { /// Get access to drawing API /// /// # Examples @@ -768,19 +781,19 @@ impl<'ui> Ui<'ui> { /// ``` #[must_use] #[doc(alias = "GetWindowDrawList")] - pub fn get_window_draw_list(&'ui self) -> DrawListMut<'ui> { + pub fn get_window_draw_list(&self) -> DrawListMut<'_> { DrawListMut::window(self) } #[must_use] #[doc(alias = "GetBackgroundDrawList")] - pub fn get_background_draw_list(&'ui self) -> DrawListMut<'ui> { + pub fn get_background_draw_list(&self) -> DrawListMut<'_> { DrawListMut::background(self) } #[must_use] #[doc(alias = "GetForegroundDrawList")] - pub fn get_foreground_draw_list(&'ui self) -> DrawListMut<'ui> { + pub fn get_foreground_draw_list(&self) -> DrawListMut<'_> { DrawListMut::foreground(self) } } diff --git a/imgui/src/list_clipper.rs b/imgui/src/list_clipper.rs index d4ba021..64a852e 100644 --- a/imgui/src/list_clipper.rs +++ b/imgui/src/list_clipper.rs @@ -22,7 +22,7 @@ impl ListClipper { self } - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> ListClipperToken<'ui> { + pub fn begin(self, ui: &Ui) -> ListClipperToken<'_> { let list_clipper = unsafe { let list_clipper = sys::ImGuiListClipper_ImGuiListClipper(); sys::ImGuiListClipper_Begin(list_clipper, self.items_count, self.items_height); @@ -34,11 +34,11 @@ impl ListClipper { pub struct ListClipperToken<'ui> { list_clipper: *mut sys::ImGuiListClipper, - _phantom: PhantomData<&'ui Ui<'ui>>, + _phantom: PhantomData<&'ui Ui>, } impl<'ui> ListClipperToken<'ui> { - fn new(_: &Ui<'ui>, list_clipper: *mut sys::ImGuiListClipper) -> Self { + fn new(_: &Ui, list_clipper: *mut sys::ImGuiListClipper) -> Self { Self { list_clipper, _phantom: PhantomData, diff --git a/imgui/src/plothistogram.rs b/imgui/src/plothistogram.rs index 0822970..8613ee2 100644 --- a/imgui/src/plothistogram.rs +++ b/imgui/src/plothistogram.rs @@ -12,11 +12,11 @@ pub struct PlotHistogram<'ui, 'p, Label, Overlay = &'static str> { scale_min: f32, scale_max: f32, graph_size: [f32; 2], - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, Label: AsRef> PlotHistogram<'ui, 'p, Label> { - pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self { + pub fn new(ui: &'ui Ui, label: Label, values: &'p [f32]) -> Self { PlotHistogram { label, values, diff --git a/imgui/src/plotlines.rs b/imgui/src/plotlines.rs index a4d8441..ec9441b 100644 --- a/imgui/src/plotlines.rs +++ b/imgui/src/plotlines.rs @@ -12,11 +12,11 @@ pub struct PlotLines<'ui, 'p, Label, Overlay = &'static str> { scale_min: f32, scale_max: f32, graph_size: [f32; 2], - ui: &'ui Ui<'ui>, + ui: &'ui Ui, } impl<'ui, 'p, Label: AsRef> PlotLines<'ui, 'p, Label> { - pub fn new(ui: &'ui Ui<'ui>, label: Label, values: &'p [f32]) -> Self { + pub fn new(ui: &'ui Ui, label: Label, values: &'p [f32]) -> Self { PlotLines { label, values, diff --git a/imgui/src/popups.rs b/imgui/src/popups.rs index e0b4288..dba4190 100644 --- a/imgui/src/popups.rs +++ b/imgui/src/popups.rs @@ -118,7 +118,7 @@ impl<'p, Label: AsRef> PopupModal<'p, Label> { /// Consume and draw the PopupModal. /// Returns the result of the closure, if it is called. #[doc(alias = "BeginPopupModal")] - pub fn build T>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build T>(self, ui: &Ui, f: F) -> Option { self.begin_popup(ui).map(|_popup| f()) } @@ -128,7 +128,7 @@ impl<'p, Label: AsRef> PopupModal<'p, Label> { /// This should be called *per frame*, whereas [`Ui::open_popup`] /// should be called *once* when you want to actual create the popup. #[doc(alias = "BeginPopupModal")] - pub fn begin_popup<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin_popup(self, ui: &Ui) -> Option> { let render = unsafe { sys::igBeginPopupModal( ui.scratch_txt(self.label), @@ -148,7 +148,7 @@ impl<'p, Label: AsRef> PopupModal<'p, Label> { } // Widgets: Popups -impl<'ui> Ui<'ui> { +impl Ui { /// Instructs ImGui to open a popup, which must be began with either [`begin_popup`](Self::begin_popup) /// or [`popup`](Self::popup). You also use this function to begin [PopupModal]. /// diff --git a/imgui/src/stacks.rs b/imgui/src/stacks.rs index 94fad58..0cc4b52 100644 --- a/imgui/src/stacks.rs +++ b/imgui/src/stacks.rs @@ -1,17 +1,14 @@ -use std::mem; -use std::os::raw::{c_char, c_void}; -use std::ptr; - -use crate::context::Context; use crate::fonts::atlas::FontId; use crate::internal::RawCast; use crate::math::MintVec4; use crate::style::{StyleColor, StyleVar}; use crate::sys; use crate::{Id, Ui}; +use std::mem; +use std::os::raw::{c_char, c_void}; /// # Parameter stacks (shared) -impl<'ui> Ui<'ui> { +impl Ui { /// Switches to the given font by pushing it to the font stack. /// /// Returns a `FontStackToken` that must be popped by calling `.pop()` @@ -180,7 +177,7 @@ unsafe fn push_style_var(style_var: StyleVar) { } /// # Parameter stacks (current window) -impl<'ui> Ui<'ui> { +impl Ui { /// Changes the item width by pushing a change to the item width stack. /// /// Returns an `ItemWidthStackToken` that may be popped by calling `.pop()` @@ -190,9 +187,9 @@ impl<'ui> Ui<'ui> { /// - `< 0.0`: `item_width` pixels relative to the right of window (-1.0 always aligns width to /// the right side) #[doc(alias = "PushItemWith")] - pub fn push_item_width(&self, item_width: f32) -> ItemWidthStackToken { + pub fn push_item_width(&self, item_width: f32) -> ItemWidthStackToken<'_> { unsafe { sys::igPushItemWidth(item_width) }; - ItemWidthStackToken { _ctx: self.ctx } + ItemWidthStackToken::new(self) } /// Sets the width of the next item. /// @@ -220,7 +217,7 @@ impl<'ui> Ui<'ui> { /// /// Returns a `TextWrapPosStackToken` that may be popped by calling `.pop()` #[doc(alias = "PushTextWrapPos")] - pub fn push_text_wrap_pos(&self) -> TextWrapPosStackToken { + pub fn push_text_wrap_pos(&self) -> TextWrapPosStackToken<'_> { self.push_text_wrap_pos_with_pos(0.0) } @@ -232,25 +229,58 @@ impl<'ui> Ui<'ui> { /// - `= 0.0`: wrap to end of window (or column) /// - `< 0.0`: no wrapping #[doc(alias = "PushTextWrapPos")] - pub fn push_text_wrap_pos_with_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken { + pub fn push_text_wrap_pos_with_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken<'_> { unsafe { sys::igPushTextWrapPos(wrap_pos_x) }; - TextWrapPosStackToken { _ctx: self.ctx } + TextWrapPosStackToken::new(self) + } + + /// Tab stop enable. + /// Allow focusing using TAB/Shift-TAB, enabled by default but you can + /// disable it for certain widgets + /// + /// Returns a [PushAllowKeyboardFocusToken] that should be dropped. + #[doc(alias = "PushAllowKeyboardFocus")] + pub fn push_allow_keyboard_focus(&self, allow: bool) -> PushAllowKeyboardFocusToken<'_> { + unsafe { sys::igPushAllowKeyboardFocus(allow) }; + PushAllowKeyboardFocusToken::new(self) + } + + /// In 'repeat' mode, button_x functions return repeated true in a typematic + /// manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). + /// Note that you can call IsItemActive() after any Button() to tell if the + /// button is held in the current frame. + /// + /// Returns a [PushButtonRepeatToken] that should be dropped. + #[doc(alias = "PushAllowKeyboardFocus")] + pub fn push_button_repeat(&self, allow: bool) -> PushButtonRepeatToken<'_> { + unsafe { sys::igPushButtonRepeat(allow) }; + PushButtonRepeatToken::new(self) } /// Changes an item flag by pushing a change to the item flag stack. /// /// Returns a `ItemFlagsStackToken` that may be popped by calling `.pop()` - #[doc(alias = "PushItemFlag")] - pub fn push_item_flag(&self, item_flag: ItemFlag) -> ItemFlagsStackToken { + /// + /// ## Deprecated + /// + /// This was deprecated in `0.9.0` because it isn't part of the dear imgui design, + /// and supporting it required a manual implementation of its drop token. + /// + /// Instead, just use [`push_allow_keyboard_focus`] and [`push_button_repeat`]. + /// + /// [`push_allow_keyboard_focus`]: Self::push_allow_keyboard_focus + /// [`push_button_repeat`]: Self::push_button_repeat + #[deprecated( + since = "0.9.0", + note = "use `push_allow_keyboard_focus` or `push_button_repeat` instead" + )] + pub fn push_item_flag(&self, item_flag: ItemFlag) -> ItemFlagsStackToken<'_> { use self::ItemFlag::*; match item_flag { AllowKeyboardFocus(v) => unsafe { sys::igPushAllowKeyboardFocus(v) }, ButtonRepeat(v) => unsafe { sys::igPushButtonRepeat(v) }, } - ItemFlagsStackToken { - discriminant: mem::discriminant(&item_flag), - _ctx: self.ctx, - } + ItemFlagsStackToken::new(self, item_flag) } } @@ -261,54 +291,78 @@ pub enum ItemFlag { ButtonRepeat(bool), } -pub struct ItemWidthStackToken { - _ctx: *const Context, -} +create_token!( + /// Tracks a window that can be ended by calling `.end()` + /// or by dropping. + pub struct ItemWidthStackToken<'ui>; -impl ItemWidthStackToken { - /// Pops a change from the item width stack + /// Ends a window #[doc(alias = "PopItemWidth")] - pub fn pop(mut self, _: &Ui<'_>) { - self._ctx = ptr::null(); - unsafe { sys::igPopItemWidth() }; - } -} + drop { sys::igPopItemWidth() } +); -/// Tracks a change pushed to the text wrap position stack -pub struct TextWrapPosStackToken { - _ctx: *const Context, -} +create_token!( + /// Tracks a window that can be ended by calling `.end()` + /// or by dropping. + pub struct TextWrapPosStackToken<'ui>; -impl TextWrapPosStackToken { - /// Pops a change from the text wrap position stack + /// Ends a window #[doc(alias = "PopTextWrapPos")] - pub fn pop(mut self, _: &Ui<'_>) { - self._ctx = ptr::null(); - unsafe { sys::igPopTextWrapPos() }; + drop { sys::igPopTextWrapPos() } +); + +create_token!( + /// Tracks a window that can be ended by calling `.end()` + /// or by dropping. + pub struct PushAllowKeyboardFocusToken<'ui>; + + /// Ends a window + #[doc(alias = "PopAllowKeyboardFocus")] + drop { sys::igPopAllowKeyboardFocus() } +); + +create_token!( + /// Tracks a window that can be ended by calling `.end()` + /// or by dropping. + pub struct PushButtonRepeatToken<'ui>; + + /// Ends a window + #[doc(alias = "PopButtonRepeat")] + drop { sys::igPopButtonRepeat() } +); + +/// Tracks a change pushed to the item flags stack. +/// +/// The "item flags" stack was a concept invented in imgui-rs that doesn't have an +/// ImGui equivalent. We're phasing these out to make imgui-rs feel simpler to use. +#[must_use] +pub struct ItemFlagsStackToken<'a>( + std::marker::PhantomData<&'a Ui>, + mem::Discriminant, +); + +impl<'a> ItemFlagsStackToken<'a> { + /// Creates a new token type. + pub(crate) fn new(_: &'a crate::Ui, kind: ItemFlag) -> Self { + Self(std::marker::PhantomData, mem::discriminant(&kind)) + } + + #[inline] + pub fn end(self) { + // left empty for drop } } -/// Tracks a change pushed to the item flags stack -pub struct ItemFlagsStackToken { - discriminant: mem::Discriminant, - _ctx: *const Context, -} - -impl ItemFlagsStackToken { - /// Pops a change from the item flags stack - - #[doc(alias = "PopAllowKeyboardFocus", alias = "PopButtonRepeat")] - pub fn pop(mut self, _: &Ui<'_>) { - self._ctx = ptr::null(); - const ALLOW_KEYBOARD_FOCUS: ItemFlag = ItemFlag::AllowKeyboardFocus(true); - const BUTTON_REPEAT: ItemFlag = ItemFlag::ButtonRepeat(true); - - if self.discriminant == mem::discriminant(&ALLOW_KEYBOARD_FOCUS) { - unsafe { sys::igPopAllowKeyboardFocus() }; - } else if self.discriminant == mem::discriminant(&BUTTON_REPEAT) { - unsafe { sys::igPopButtonRepeat() }; - } else { - unreachable!(); +impl Drop for ItemFlagsStackToken<'_> { + fn drop(&mut self) { + unsafe { + if self.1 == mem::discriminant(&ItemFlag::AllowKeyboardFocus(true)) { + sys::igPopAllowKeyboardFocus(); + } else if self.1 == mem::discriminant(&ItemFlag::ButtonRepeat(true)) { + sys::igPopButtonRepeat(); + } else { + unreachable!(); + } } } } @@ -330,7 +384,7 @@ impl IdStackToken<'_> { } /// # ID stack -impl<'ui> Ui<'ui> { +impl<'ui> Ui { /// Pushes an identifier to the ID stack. /// This can be called with an integer, a string, or a pointer. /// @@ -408,7 +462,7 @@ impl<'ui> Ui<'ui> { /// }); /// ``` #[doc(alias = "PushId")] - pub fn push_id<'a, I: Into>>(&self, id: I) -> IdStackToken<'ui> { + pub fn push_id<'a, I: Into>>(&'ui self, id: I) -> IdStackToken<'ui> { let id = id.into(); unsafe { diff --git a/imgui/src/string.rs b/imgui/src/string.rs index d124d85..af6557b 100644 --- a/imgui/src/string.rs +++ b/imgui/src/string.rs @@ -7,16 +7,16 @@ use std::{fmt, ptr}; /// this is the unsafe cell upon which we build our abstraction. #[derive(Debug)] -pub(crate) struct UiBuffer { - buffer: Vec, - max_len: usize, +pub struct UiBuffer { + pub buffer: Vec, + pub max_len: usize, } impl UiBuffer { /// Creates a new max buffer with the given length. - pub fn new(max_len: usize) -> Self { + pub const fn new(max_len: usize) -> Self { Self { - buffer: Vec::with_capacity(max_len), + buffer: Vec::new(), max_len, } } diff --git a/imgui/src/tables.rs b/imgui/src/tables.rs index ebd52dd..a5a9503 100644 --- a/imgui/src/tables.rs +++ b/imgui/src/tables.rs @@ -249,7 +249,7 @@ pub enum TableSortDirection { Descending, } -impl<'ui> Ui<'ui> { +impl Ui { /// Begins a table with no flags and with standard sizing contraints. /// /// This does no work on styling the headers (the top row) -- see either @@ -263,7 +263,7 @@ impl<'ui> Ui<'ui> { &self, str_id: impl AsRef, column_count: usize, - ) -> Option> { + ) -> Option> { self.begin_table_with_flags(str_id, column_count, TableFlags::empty()) } @@ -281,7 +281,7 @@ impl<'ui> Ui<'ui> { str_id: impl AsRef, column_count: usize, flags: TableFlags, - ) -> Option> { + ) -> Option> { self.begin_table_with_sizing(str_id, column_count, flags, [0.0, 0.0], 0.0) } @@ -302,7 +302,7 @@ impl<'ui> Ui<'ui> { flags: TableFlags, outer_size: [f32; 2], inner_width: f32, - ) -> Option> { + ) -> Option> { unsafe { sys::igBeginTable( self.scratch_txt(str_id), @@ -324,7 +324,7 @@ impl<'ui> Ui<'ui> { &self, str_id: impl AsRef, column_data: [TableColumnSetup<'a, Name>; N], - ) -> Option> { + ) -> Option> { self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty()) } @@ -338,7 +338,7 @@ impl<'ui> Ui<'ui> { str_id: impl AsRef, column_data: [TableColumnSetup<'a, Name>; N], flags: TableFlags, - ) -> Option> { + ) -> Option> { self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0) } @@ -354,7 +354,7 @@ impl<'ui> Ui<'ui> { flags: TableFlags, outer_size: [f32; 2], inner_width: f32, - ) -> Option> { + ) -> Option> { self.begin_table_with_sizing(str_id, N, flags, outer_size, inner_width) .map(|data| { for value in column_data { @@ -769,7 +769,7 @@ impl<'a, Name: AsRef> TableColumnSetup<'a, Name> { /// [should_sort]: Self::should_sort /// [specs]: Self::specs /// [set_sorted]: Self::set_sorted -pub struct TableSortSpecsMut<'ui>(*mut sys::ImGuiTableSortSpecs, PhantomData>); +pub struct TableSortSpecsMut<'ui>(*mut sys::ImGuiTableSortSpecs, PhantomData<&'ui Ui>); impl TableSortSpecsMut<'_> { /// Gets the specs for a given sort. In most scenarios, this will be a slice of 1 entry. diff --git a/imgui/src/tokens.rs b/imgui/src/tokens.rs index 7cf20b4..01adf84 100644 --- a/imgui/src/tokens.rs +++ b/imgui/src/tokens.rs @@ -19,11 +19,11 @@ macro_rules! create_token { ) => { #[must_use] $(#[$struct_meta])* - pub struct $token_name<'a>($crate::__core::marker::PhantomData>); + pub struct $token_name<'a>($crate::__core::marker::PhantomData<&'a crate::Ui>); impl<'a> $token_name<'a> { /// Creates a new token type. - pub(crate) fn new(_: &crate::Ui<'a>) -> Self { + pub(crate) fn new(_: &'a crate::Ui) -> Self { Self(std::marker::PhantomData) } diff --git a/imgui/src/utils.rs b/imgui/src/utils.rs index b977c6d..144de1b 100644 --- a/imgui/src/utils.rs +++ b/imgui/src/utils.rs @@ -25,7 +25,7 @@ bitflags! { } /// # Item/widget utilities -impl<'ui> Ui<'ui> { +impl Ui { /// Returns `true` if the last item is hovered #[doc(alias = "IsItemHovered")] pub fn is_item_hovered(&self) -> bool { @@ -142,7 +142,7 @@ impl<'ui> Ui<'ui> { } /// # Miscellaneous utilities -impl<'ui> Ui<'ui> { +impl Ui { /// Returns `true` if the rectangle (of given size, starting from cursor position) is visible #[doc(alias = "IsRectVisibleNil")] pub fn is_cursor_rect_visible(&self, size: impl Into) -> bool { @@ -177,7 +177,7 @@ impl<'ui> Ui<'ui> { /// style object. #[doc(alias = "GetStyle")] pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] { - self.ctx.style()[style_color] + unsafe { self.style() }.colors[style_color as usize] } /// Returns a shared reference to the current [`Style`]. @@ -193,6 +193,7 @@ impl<'ui> Ui<'ui> { /// pop. The [`clone_style`](Ui::clone_style) version may instead be used to avoid `unsafe`. #[doc(alias = "GetStyle")] pub unsafe fn style(&self) -> &Style { - self.ctx.style() + // safe because Style is a transparent wrapper around sys::ImGuiStyle + &*(sys::igGetStyle() as *const Style) } } diff --git a/imgui/src/widget/color_editors.rs b/imgui/src/widget/color_editors.rs index e7157a5..e02e811 100644 --- a/imgui/src/widget/color_editors.rs +++ b/imgui/src/widget/color_editors.rs @@ -326,7 +326,7 @@ where /// Builds the color editor. /// /// Returns true if the color value was changed. - pub fn build(mut self, ui: &Ui<'_>) -> bool { + pub fn build(mut self, ui: &Ui) -> bool { // if let EditableColor::Float3(_) = self.value { self.flags.insert(ColorEditFlags::NO_ALPHA); @@ -508,7 +508,7 @@ where /// Builds the color editor. /// /// Returns true if the color value was changed. - pub fn build(self, ui: &Ui<'_>) -> bool { + pub fn build(self, ui: &Ui) -> bool { let as_vec4: MintVec4 = (*self.value).into(); let mut as_vec4: [f32; 4] = as_vec4.into(); @@ -694,7 +694,7 @@ where /// Builds the color picker. /// /// Returns true if the color value was changed. - pub fn build(mut self, ui: &Ui<'_>) -> bool { + pub fn build(mut self, ui: &Ui) -> bool { self.flags.insert(ColorEditFlags::NO_ALPHA); let mut value: [f32; 3] = (*self.value).into().into(); let changed = unsafe { @@ -886,7 +886,7 @@ where /// Builds the color picker. /// /// Returns true if the color value was changed. - pub fn build(mut self, ui: &Ui<'_>) -> bool { + pub fn build(mut self, ui: &Ui) -> bool { self.flags.insert(ColorEditFlags::NO_ALPHA); let mut value: [f32; 4] = (*self.value).into().into(); let ref_color = self.ref_color.map(|c| c.as_ptr()).unwrap_or(ptr::null()); @@ -1009,7 +1009,7 @@ impl> ColorButton { /// Builds the color button. /// /// Returns true if this color button was clicked. - pub fn build(self, ui: &Ui<'_>) -> bool { + pub fn build(self, ui: &Ui) -> bool { unsafe { sys::igColorButton( ui.scratch_txt(self.desc_id), @@ -1022,7 +1022,7 @@ impl> ColorButton { } /// # Widgets: Color Editor/Picker -impl<'ui> Ui<'ui> { +impl Ui { /// Initializes current color editor/picker options (generally on application startup) if you /// want to select a default format, picker type, etc. Users will be able to change many /// settings, unless you use .options(false) in your widget builders. diff --git a/imgui/src/widget/combo_box.rs b/imgui/src/widget/combo_box.rs index 342ef69..48cfdfe 100644 --- a/imgui/src/widget/combo_box.rs +++ b/imgui/src/widget/combo_box.rs @@ -142,7 +142,7 @@ impl, Preview: AsRef> ComboBox { /// /// Returns `None` if the combo box is not open and no content should be rendered. #[must_use] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin(self, ui: &Ui) -> Option> { let should_render = unsafe { if let Some(preview_value) = self.preview_value { let (ptr_one, ptr_two) = ui.scratch_txt_two(self.label, preview_value); @@ -162,7 +162,7 @@ impl, Preview: AsRef> ComboBox { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the combo box is not open. - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_combo| f()) } } @@ -177,7 +177,7 @@ create_token!( ); /// # Convenience functions -impl<'ui> Ui<'ui> { +impl Ui { /// Creates a combo box which can be appended to with `Selectable::new`. /// /// If you do not want to provide a preview, use [`begin_combo_no_preview`]. If you want @@ -193,7 +193,7 @@ impl<'ui> Ui<'ui> { &self, label: impl AsRef, preview_value: impl AsRef, - ) -> Option> { + ) -> Option> { self.begin_combo_with_flags(label, preview_value, ComboBoxFlags::empty()) } @@ -213,7 +213,7 @@ impl<'ui> Ui<'ui> { label: impl AsRef, preview_value: impl AsRef, flags: ComboBoxFlags, - ) -> Option> { + ) -> Option> { self._begin_combo(label, Some(preview_value), flags) } @@ -231,7 +231,7 @@ impl<'ui> Ui<'ui> { /// [begin_combo_no_preview_with_flags]: Ui::begin_combo_no_preview_with_flags #[must_use] #[doc(alias = "BeginCombo")] - pub fn begin_combo_no_preview(&self, label: impl AsRef) -> Option> { + pub fn begin_combo_no_preview(&self, label: impl AsRef) -> Option> { self.begin_combo_no_preview_with_flags(label, ComboBoxFlags::empty()) } @@ -250,7 +250,7 @@ impl<'ui> Ui<'ui> { &self, label: impl AsRef, flags: ComboBoxFlags, - ) -> Option> { + ) -> Option> { self._begin_combo(label, Option::<&'static str>::None, flags) } @@ -260,7 +260,7 @@ impl<'ui> Ui<'ui> { label: impl AsRef, preview_value: Option>, flags: ComboBoxFlags, - ) -> Option> { + ) -> Option> { let should_render = unsafe { let (ptr_one, ptr_two) = self.scratch_txt_with_opt(label, preview_value); sys::igBeginCombo(ptr_one, ptr_two, flags.bits() as i32) diff --git a/imgui/src/widget/drag.rs b/imgui/src/widget/drag.rs index a861365..af25ca1 100644 --- a/imgui/src/widget/drag.rs +++ b/imgui/src/widget/drag.rs @@ -66,7 +66,7 @@ impl, T: DataTypeKind, F: AsRef> Drag { /// Builds a drag slider that is bound to the given value. /// /// Returns true if the slider value was changed. - pub fn build(self, ui: &Ui<'_>, value: &mut T) -> bool { + pub fn build(self, ui: &Ui, value: &mut T) -> bool { unsafe { let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format); @@ -91,7 +91,7 @@ impl, T: DataTypeKind, F: AsRef> Drag { /// Builds a horizontal array of multiple drag sliders attached to the given slice. /// /// Returns true if any slider value was changed. - pub fn build_array(self, ui: &Ui<'_>, values: &mut [T]) -> bool { + pub fn build_array(self, ui: &Ui, values: &mut [T]) -> bool { unsafe { let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format); @@ -208,14 +208,14 @@ where /// /// Returns true if the slider value was changed. #[doc(alias = "DragFloatRange2")] - pub fn build(self, ui: &Ui<'_>, min: &mut f32, max: &mut f32) -> bool { + pub fn build(self, ui: &Ui, min: &mut f32, max: &mut f32) -> bool { let label; let mut display_format = std::ptr::null(); let mut max_display_format = std::ptr::null(); // we do this ourselves the long way... unsafe { - let buffer = &mut *ui.buffer.get(); + let buffer = &mut *ui.scratch_buffer().get(); buffer.refresh_buffer(); label = buffer.push(self.label); @@ -251,14 +251,14 @@ where /// /// Returns true if the slider value was changed. #[doc(alias = "DragIntRange2")] - pub fn build(self, ui: &Ui<'_>, min: &mut i32, max: &mut i32) -> bool { + pub fn build(self, ui: &Ui, min: &mut i32, max: &mut i32) -> bool { unsafe { let label; let mut display_format = std::ptr::null(); let mut max_display_format = std::ptr::null(); // we do this ourselves the long way... - let buffer = &mut *ui.buffer.get(); + let buffer = &mut *ui.scratch_buffer().get(); buffer.refresh_buffer(); label = buffer.push(self.label); diff --git a/imgui/src/widget/image.rs b/imgui/src/widget/image.rs index 4e2d115..d5aa4b3 100644 --- a/imgui/src/widget/image.rs +++ b/imgui/src/widget/image.rs @@ -58,7 +58,7 @@ impl Image { self } /// Builds the image - pub fn build(self, _: &Ui<'_>) { + pub fn build(self, _: &Ui) { unsafe { sys::igImage( self.texture_id.id() as *mut c_void, @@ -136,7 +136,7 @@ impl ImageButton { self } /// Builds the image button - pub fn build(self, _: &Ui<'_>) -> bool { + pub fn build(self, _: &Ui) -> bool { unsafe { sys::igImageButton( self.texture_id.id() as *mut c_void, diff --git a/imgui/src/widget/list_box.rs b/imgui/src/widget/list_box.rs index 922d871..e01bdc2 100644 --- a/imgui/src/widget/list_box.rs +++ b/imgui/src/widget/list_box.rs @@ -39,7 +39,7 @@ impl> ListBox { /// /// Returns `None` if the list box is not open and no content should be rendered. #[must_use] - pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn begin(self, ui: &Ui) -> Option> { let should_render = unsafe { sys::igBeginListBox(ui.scratch_txt(self.label), self.size.into()) }; if should_render { @@ -52,7 +52,7 @@ impl> ListBox { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the list box is not open. - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_list| f()) } } @@ -71,7 +71,7 @@ impl> ListBox { /// Builds a simple list box for choosing from a slice of values pub fn build_simple( self, - ui: &Ui<'_>, + ui: &Ui, current_item: &mut usize, items: &[V], label_fn: &L, diff --git a/imgui/src/widget/menu.rs b/imgui/src/widget/menu.rs index 0ac02e5..0b4a263 100644 --- a/imgui/src/widget/menu.rs +++ b/imgui/src/widget/menu.rs @@ -3,7 +3,7 @@ use crate::sys; use crate::Ui; /// # Widgets: Menus -impl<'ui> Ui<'ui> { +impl Ui { /// Creates and starts appending to a full-screen menu bar. /// /// Returns `Some(MainMenuBarToken)` if the menu bar is visible. After content has been @@ -12,7 +12,7 @@ impl<'ui> Ui<'ui> { /// Returns `None` if the menu bar is not visible and no content should be rendered. #[must_use] #[doc(alias = "BeginMainMenuBar")] - pub fn begin_main_menu_bar(&self) -> Option> { + pub fn begin_main_menu_bar(&self) -> Option> { if unsafe { sys::igBeginMainMenuBar() } { Some(MainMenuBarToken::new(self)) } else { @@ -167,7 +167,7 @@ impl, Shortcut: AsRef> MenuItem { /// /// Returns true if the menu item is activated. #[doc(alias = "MenuItemBool")] - pub fn build(self, ui: &Ui<'_>) -> bool { + pub fn build(self, ui: &Ui) -> bool { unsafe { let (label, shortcut) = ui.scratch_txt_with_opt(self.label, self.shortcut); sys::igMenuItem_Bool(label, shortcut, self.selected, self.enabled) @@ -176,7 +176,7 @@ impl, Shortcut: AsRef> MenuItem { #[doc(alias = "MenuItemBool")] /// Builds the menu item using a mutable reference to selected state. - pub fn build_with_ref(self, ui: &Ui<'_>, selected: &mut bool) -> bool { + pub fn build_with_ref(self, ui: &Ui, selected: &mut bool) -> bool { if self.selected(*selected).build(ui) { *selected = !*selected; true diff --git a/imgui/src/widget/misc.rs b/imgui/src/widget/misc.rs index f79e128..288c341 100644 --- a/imgui/src/widget/misc.rs +++ b/imgui/src/widget/misc.rs @@ -19,7 +19,7 @@ bitflags!( ); /// # Widgets: Miscellaneous -impl<'ui> Ui<'ui> { +impl Ui { /// Renders a clickable button. /// /// Returns true if this button was clicked. diff --git a/imgui/src/widget/progress_bar.rs b/imgui/src/widget/progress_bar.rs index eb641ef..514127d 100644 --- a/imgui/src/widget/progress_bar.rs +++ b/imgui/src/widget/progress_bar.rs @@ -62,7 +62,7 @@ impl> ProgressBar { } /// Builds the progress bar - pub fn build(self, ui: &Ui<'_>) { + pub fn build(self, ui: &Ui) { unsafe { sys::igProgressBar( self.fraction, diff --git a/imgui/src/widget/selectable.rs b/imgui/src/widget/selectable.rs index 48eceaa..2bfe93b 100644 --- a/imgui/src/widget/selectable.rs +++ b/imgui/src/widget/selectable.rs @@ -108,7 +108,7 @@ impl> Selectable { /// Builds the selectable. /// /// Returns true if the selectable was clicked. - pub fn build(self, ui: &Ui<'_>) -> bool { + pub fn build(self, ui: &Ui) -> bool { unsafe { sys::igSelectable_Bool( ui.scratch_txt(self.label), @@ -120,7 +120,7 @@ impl> Selectable { } /// Builds the selectable using a mutable reference to selected state. - pub fn build_with_ref(self, ui: &Ui<'_>, selected: &mut bool) -> bool { + pub fn build_with_ref(self, ui: &Ui, selected: &mut bool) -> bool { if self.selected(*selected).build(ui) { *selected = !*selected; true diff --git a/imgui/src/widget/slider.rs b/imgui/src/widget/slider.rs index 5b7d1c9..c473730 100644 --- a/imgui/src/widget/slider.rs +++ b/imgui/src/widget/slider.rs @@ -96,7 +96,7 @@ where /// Builds a slider that is bound to the given value. /// /// Returns true if the slider value was changed. - pub fn build(self, ui: &Ui<'_>, value: &mut Data) -> bool { + pub fn build(self, ui: &Ui, value: &mut Data) -> bool { unsafe { let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); @@ -114,7 +114,7 @@ where /// Builds a horizontal array of multiple sliders attached to the given slice. /// /// Returns true if any slider value was changed. - pub fn build_array(self, ui: &Ui<'_>, values: &mut [Data]) -> bool { + pub fn build_array(self, ui: &Ui, values: &mut [Data]) -> bool { unsafe { let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); @@ -222,7 +222,7 @@ where /// Builds a vertical slider that is bound to the given value. /// /// Returns true if the slider value was changed. - pub fn build(self, ui: &Ui<'_>, value: &mut Data) -> bool { + pub fn build(self, ui: &Ui, value: &mut Data) -> bool { unsafe { let (label, display_format) = ui.scratch_txt_with_opt(self.label, self.display_format); @@ -326,7 +326,7 @@ where /// Builds an angle slider that is bound to the given value (in radians). /// /// Returns true if the slider value was changed. - pub fn build(self, ui: &Ui<'_>, value_rad: &mut f32) -> bool { + pub fn build(self, ui: &Ui, value_rad: &mut f32) -> bool { unsafe { let (label, display_format) = ui.scratch_txt_two(self.label, self.display_format); diff --git a/imgui/src/widget/tab.rs b/imgui/src/widget/tab.rs index b1bedce..54b43a0 100644 --- a/imgui/src/widget/tab.rs +++ b/imgui/src/widget/tab.rs @@ -87,7 +87,7 @@ impl> TabBar { } #[must_use] - pub fn begin<'ui>(self, ui: &'ui Ui<'_>) -> Option> { + pub fn begin(self, ui: &Ui) -> Option> { ui.tab_bar_with_flags(self.id, self.flags) } @@ -95,7 +95,7 @@ impl> TabBar { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if no tabbar content is visible - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } @@ -144,7 +144,7 @@ impl<'a, T: AsRef> TabItem<'a, T> { } #[must_use] - pub fn begin<'ui>(self, ui: &'ui Ui<'_>) -> Option> { + pub fn begin(self, ui: &Ui) -> Option> { ui.tab_item_with_flags(self.label, self.opened, self.flags) } @@ -152,7 +152,7 @@ impl<'a, T: AsRef> TabItem<'a, T> { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the tab item is not selected - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } @@ -166,7 +166,7 @@ create_token!( drop { sys::igEndTabItem() } ); -impl Ui<'_> { +impl Ui { /// Creates a tab bar and returns a tab bar token, allowing you to append /// Tab items afterwards. This passes no flags. To pass flags explicitly, /// use [tab_bar_with_flags](Self::tab_bar_with_flags). diff --git a/imgui/src/widget/text.rs b/imgui/src/widget/text.rs index 99bb0d4..abe38be 100644 --- a/imgui/src/widget/text.rs +++ b/imgui/src/widget/text.rs @@ -13,7 +13,7 @@ fn fmt_ptr() -> *const c_char { } /// # Widgets: Text -impl<'ui> Ui<'ui> { +impl Ui { /// Renders simple text #[doc(alias = "TextUnformatted")] pub fn text>(&self, text: T) { diff --git a/imgui/src/widget/tree.rs b/imgui/src/widget/tree.rs index 06abafc..4f18b16 100644 --- a/imgui/src/widget/tree.rs +++ b/imgui/src/widget/tree.rs @@ -241,7 +241,7 @@ impl, L: AsRef> TreeNode { /// rendered, the token can be popped by calling `.pop()`. /// /// Returns `None` if the tree node is not open and no content should be rendered. - pub fn push<'ui>(self, ui: &Ui<'ui>) -> Option> { + pub fn push(self, ui: &Ui) -> Option> { let open = unsafe { if self.opened_cond != Condition::Never { sys::igSetNextItemOpen(self.opened, self.opened_cond as i32); @@ -282,7 +282,7 @@ impl, L: AsRef> TreeNode { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the tree node is not open. - pub fn build R>(self, ui: &Ui<'_>, f: F) -> Option { + pub fn build R>(self, ui: &Ui, f: F) -> Option { self.push(ui).map(|_node| f()) } } @@ -292,11 +292,11 @@ impl, L: AsRef> TreeNode { /// If `TreeNodeFlags::NO_TREE_PUSH_ON_OPEN` was used when this token was created, calling `.pop()` /// is not mandatory and is a no-op. #[must_use] -pub struct TreeNodeToken<'a>(core::marker::PhantomData>, bool); +pub struct TreeNodeToken<'a>(core::marker::PhantomData<&'a crate::Ui>, bool); impl<'a> TreeNodeToken<'a> { /// Creates a new token type. This takes a bool for the no-op variant on NO_TREE_PUSH_ON_OPEN. - pub(crate) fn new(_: &crate::Ui<'a>, execute_drop: bool) -> Self { + pub(crate) fn new(_: &crate::Ui, execute_drop: bool) -> Self { Self(std::marker::PhantomData, execute_drop) } @@ -408,7 +408,7 @@ impl> CollapsingHeader { /// /// This is the same as [build](Self::build) but is provided for consistent naming. #[must_use] - pub fn begin(self, ui: &Ui<'_>) -> bool { + pub fn begin(self, ui: &Ui) -> bool { self.build(ui) } @@ -419,7 +419,7 @@ impl> CollapsingHeader { /// This is the same as [build_with_close_button](Self::build_with_close_button) /// but is provided for consistent naming. #[must_use] - pub fn begin_with_close_button(self, ui: &Ui<'_>, opened: &mut bool) -> bool { + pub fn begin_with_close_button(self, ui: &Ui, opened: &mut bool) -> bool { self.build_with_close_button(ui, opened) } @@ -428,7 +428,7 @@ impl> CollapsingHeader { /// Returns true if the collapsing header is open and content should be rendered. #[must_use] #[inline] - pub fn build(self, ui: &Ui<'_>) -> bool { + pub fn build(self, ui: &Ui) -> bool { unsafe { sys::igCollapsingHeader_TreeNodeFlags( ui.scratch_txt(self.label), @@ -442,7 +442,7 @@ impl> CollapsingHeader { /// Returns true if the collapsing header is open and content should be rendered. #[must_use] #[inline] - pub fn build_with_close_button(self, ui: &Ui<'_>, opened: &mut bool) -> bool { + pub fn build_with_close_button(self, ui: &Ui, opened: &mut bool) -> bool { unsafe { sys::igCollapsingHeader_BoolPtr( ui.scratch_txt(self.label), @@ -453,7 +453,7 @@ impl> CollapsingHeader { } } -impl Ui<'_> { +impl Ui { /// Constructs a new collapsing header #[doc(alias = "CollapsingHeader")] pub fn collapsing_header(&self, label: impl AsRef, flags: TreeNodeFlags) -> bool { diff --git a/imgui/src/window/child_window.rs b/imgui/src/window/child_window.rs index 8b83df4..5694305 100644 --- a/imgui/src/window/child_window.rs +++ b/imgui/src/window/child_window.rs @@ -9,7 +9,7 @@ use crate::Ui; #[derive(Copy, Clone, Debug)] #[must_use] pub struct ChildWindow<'ui, Label> { - ui: &'ui Ui<'ui>, + ui: &'ui Ui, name: Label, flags: WindowFlags, size: [f32; 2], @@ -22,7 +22,7 @@ pub struct ChildWindow<'ui, Label> { impl<'ui, Label: AsRef> ChildWindow<'ui, Label> { /// Creates a new child window builder with the given ID #[doc(alias = "BeginChildID")] - pub fn new(ui: &'ui Ui<'ui>, name: Label) -> ChildWindow<'ui, Label> { + pub fn new(ui: &'ui Ui, name: Label) -> ChildWindow<'ui, Label> { ChildWindow { ui, name, diff --git a/imgui/src/window/content_region.rs b/imgui/src/window/content_region.rs index 40c2190..27270e2 100644 --- a/imgui/src/window/content_region.rs +++ b/imgui/src/window/content_region.rs @@ -2,7 +2,7 @@ use crate::sys; use crate::Ui; /// # Content region -impl<'ui> Ui<'ui> { +impl Ui { /// Returns the current content boundaries (in *window coordinates*) #[doc(alias = "GetContentRegionMax")] pub fn content_region_max(&self) -> [f32; 2] { diff --git a/imgui/src/window/mod.rs b/imgui/src/window/mod.rs index 6183ca8..00e7f65 100644 --- a/imgui/src/window/mod.rs +++ b/imgui/src/window/mod.rs @@ -111,7 +111,7 @@ bitflags! { } /// # Window utilities -impl<'ui> Ui<'ui> { +impl Ui { /// Returns true if the current window appeared during this frame #[doc(alias = "IsWindowAppearing")] pub fn is_window_appearing(&self) -> bool { @@ -162,7 +162,7 @@ impl<'ui> Ui<'ui> { #[derive(Debug)] #[must_use] pub struct Window<'ui, 'a, Label> { - ui: &'ui Ui<'ui>, + ui: &'ui Ui, name: Label, opened: Option<&'a mut bool>, flags: WindowFlags, @@ -181,7 +181,7 @@ pub struct Window<'ui, 'a, Label> { impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { /// Typically created via [`Ui::window`] - pub fn new(ui: &'ui Ui<'ui>, name: Label) -> Self { + pub fn new(ui: &'ui Ui, name: Label) -> Self { Window { ui, name, diff --git a/imgui/src/window/scroll.rs b/imgui/src/window/scroll.rs index 386002a..cd9174a 100644 --- a/imgui/src/window/scroll.rs +++ b/imgui/src/window/scroll.rs @@ -2,7 +2,7 @@ use crate::sys; use crate::Ui; /// # Window scrolling -impl<'ui> Ui<'ui> { +impl Ui { /// Returns the horizontal scrolling position. /// /// Value is between 0.0 and self.scroll_max_x().