From 9516e622be1fed5a724b82ed5113118592cb627b Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Thu, 27 Jun 2019 18:18:57 +0300 Subject: [PATCH] Pull first part of 0.1 context API --- Cargo.toml | 2 + imgui-examples/Cargo.lock | 2 + imgui-examples/examples/support_gfx/mod.rs | 4 +- imgui-gfx-renderer/src/lib.rs | 4 +- imgui-glium-examples/Cargo.lock | 2 + imgui-glium-examples/examples/support/mod.rs | 4 +- imgui-glium-renderer/src/lib.rs | 6 +- imgui-winit-support/src/lib.rs | 30 +- src/context.rs | 338 +++++++++++++++++++ src/lib.rs | 93 ++--- src/test.rs | 15 + 11 files changed, 402 insertions(+), 98 deletions(-) create mode 100644 src/context.rs create mode 100644 src/test.rs diff --git a/Cargo.toml b/Cargo.toml index e5db611..bcf35d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ travis-ci = { repository = "Gekkio/imgui-rs" } [dependencies] imgui-sys = { version = "0.0.24-pre", path = "imgui-sys" } +lazy_static = "1.1" +parking_lot = "0.7" [dev-dependencies] memoffset = "0.3" diff --git a/imgui-examples/Cargo.lock b/imgui-examples/Cargo.lock index aa01a69..590bc0c 100644 --- a/imgui-examples/Cargo.lock +++ b/imgui-examples/Cargo.lock @@ -356,6 +356,8 @@ name = "imgui" version = "0.0.24-pre" dependencies = [ "imgui-sys 0.0.24-pre", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/imgui-examples/examples/support_gfx/mod.rs b/imgui-examples/examples/support_gfx/mod.rs index 82efb91..b7dd7fb 100644 --- a/imgui-examples/examples/support_gfx/mod.rs +++ b/imgui-examples/examples/support_gfx/mod.rs @@ -1,4 +1,4 @@ -use imgui::{FontGlyphRange, ImFontConfig, ImGui, Ui}; +use imgui::{FontGlyphRange, ImFontConfig, Context, Ui}; use imgui_gfx_renderer::{Renderer, Shaders}; use imgui_winit_support; use std::time::Instant; @@ -42,7 +42,7 @@ pub fn run bool>(title: String, clear_color: [f32; 4], mut run_ } }; - let mut imgui = ImGui::init(); + let mut imgui = Context::create(); { // Fix incorrect colors with sRGB framebuffer fn imgui_gamma_to_linear(col: [f32; 4]) -> [f32; 4] { diff --git a/imgui-gfx-renderer/src/lib.rs b/imgui-gfx-renderer/src/lib.rs index 55bdf26..9c112df 100644 --- a/imgui-gfx-renderer/src/lib.rs +++ b/imgui-gfx-renderer/src/lib.rs @@ -4,7 +4,7 @@ use gfx::pso::{PipelineData, PipelineState}; use gfx::texture::{FilterMethod, SamplerInfo, WrapMode}; use gfx::traits::FactoryExt; use gfx::{CommandBuffer, Encoder, Factory, IntoIndexBuffer, Rect, Resources, Slice}; -use imgui::{DrawList, FrameSize, ImDrawIdx, ImDrawVert, ImGui, ImTexture, Textures, Ui}; +use imgui::{Context, DrawList, FrameSize, ImDrawIdx, ImDrawVert, ImTexture, Textures, Ui}; pub type RendererResult = Result; @@ -190,7 +190,7 @@ pub struct Renderer { impl Renderer { pub fn init>( - imgui: &mut ImGui, + imgui: &mut Context, factory: &mut F, shaders: Shaders, out: RenderTargetView, diff --git a/imgui-glium-examples/Cargo.lock b/imgui-glium-examples/Cargo.lock index f2cc28c..0516836 100644 --- a/imgui-glium-examples/Cargo.lock +++ b/imgui-glium-examples/Cargo.lock @@ -372,6 +372,8 @@ name = "imgui" version = "0.0.24-pre" dependencies = [ "imgui-sys 0.0.24-pre", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/imgui-glium-examples/examples/support/mod.rs b/imgui-glium-examples/examples/support/mod.rs index 8fdc0fe..5a81f25 100644 --- a/imgui-glium-examples/examples/support/mod.rs +++ b/imgui-glium-examples/examples/support/mod.rs @@ -2,7 +2,7 @@ use glium::{ backend::{Context, Facade}, Texture2d, }; -use imgui::{FontGlyphRange, ImFontConfig, ImGui, Ui}; +use imgui::{FontGlyphRange, ImFontConfig, self, Ui}; use imgui_winit_support; use std::rc::Rc; use std::time::Instant; @@ -26,7 +26,7 @@ where let gl_window = display.gl_window(); let window = gl_window.window(); - let mut imgui = ImGui::init(); + let mut imgui = imgui::Context::create(); imgui.set_ini_filename(None); // In the examples we only use integer DPI factors, because the UI can get very blurry diff --git a/imgui-glium-renderer/src/lib.rs b/imgui-glium-renderer/src/lib.rs index b3f8579..ac7fedf 100644 --- a/imgui-glium-renderer/src/lib.rs +++ b/imgui-glium-renderer/src/lib.rs @@ -4,7 +4,7 @@ use glium::program; use glium::texture; use glium::vertex; use glium::{uniform, DrawError, IndexBuffer, Program, Surface, Texture2d, VertexBuffer}; -use imgui::{DrawList, FrameSize, ImGui, ImTexture, Textures, Ui}; +use imgui::{self, DrawList, FrameSize, ImTexture, Textures, Ui}; use std::borrow::Cow; use std::fmt; use std::rc::Rc; @@ -71,7 +71,7 @@ pub struct Renderer { } impl Renderer { - pub fn init(imgui: &mut ImGui, ctx: &F) -> RendererResult { + pub fn init(imgui: &mut imgui::Context, ctx: &F) -> RendererResult { let device_objects = DeviceObjects::init(imgui, ctx)?; Ok(Renderer { ctx: Rc::clone(ctx.get_context()), @@ -222,7 +222,7 @@ fn compile_default_program( } impl DeviceObjects { - pub fn init(im_gui: &mut ImGui, ctx: &F) -> RendererResult { + pub fn init(im_gui: &mut imgui::Context, ctx: &F) -> RendererResult { use glium::texture::{ClientFormat, RawImage2d}; let program = compile_default_program(ctx)?; diff --git a/imgui-winit-support/src/lib.rs b/imgui-winit-support/src/lib.rs index 368390a..e658dec 100644 --- a/imgui-winit-support/src/lib.rs +++ b/imgui-winit-support/src/lib.rs @@ -5,10 +5,10 @@ //! In your initialization code call `configure_keys`: //! //! ```rust,no_run -//! use imgui::ImGui; +//! use imgui::Context; //! //! # fn main() { -//! let mut imgui = ImGui::init(); +//! let mut imgui = Context::create(); //! imgui_winit_support::configure_keys(&mut imgui); //! # } //! ``` @@ -17,11 +17,11 @@ //! you need to do is pass each event to `imgui_winit_support` as well: //! //! ```rust,no_run -//! # use imgui::ImGui; +//! # use imgui::Context; //! # use winit::EventsLoop; //! # fn main() { //! # let mut events_loop = EventsLoop::new(); -//! # let mut imgui = ImGui::init(); +//! # let mut imgui = Context::create(); //! # let window_hidpi_factor = 1.0; //! # let app_hidpi_factor = 1.0; //! events_loop.poll_events(|event| { @@ -45,11 +45,11 @@ //! For example, you might want to customize mouse wheel line scrolling amount: //! //! ```rust,no_run -//! # use imgui::ImGui; +//! # use imgui::Context; //! # use winit::{EventsLoop, Event, WindowEvent, MouseScrollDelta, TouchPhase}; //! # fn main() { //! # let mut events_loop = EventsLoop::new(); -//! # let mut imgui = ImGui::init(); +//! # let mut imgui = Context::create(); //! # let window_hidpi_factor = 1.0; //! # let app_hidpi_factor = 1.0; //! events_loop.poll_events(|event| { @@ -81,14 +81,14 @@ //! # } //! ``` -use imgui::{FrameSize, ImGui, ImGuiKey, ImGuiMouseCursor}; +use imgui::{Context, FrameSize, ImGuiKey, ImGuiMouseCursor}; use winit::{ ElementState, Event, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta, TouchPhase, VirtualKeyCode, Window, WindowEvent, }; /// Configure imgui key map with winit `VirtualKeyCode` values -pub fn configure_keys(imgui: &mut ImGui) { +pub fn configure_keys(imgui: &mut Context) { imgui.set_imgui_key(ImGuiKey::Tab, VirtualKeyCode::Tab as _); imgui.set_imgui_key(ImGuiKey::LeftArrow, VirtualKeyCode::Left as _); imgui.set_imgui_key(ImGuiKey::RightArrow, VirtualKeyCode::Right as _); @@ -111,7 +111,7 @@ pub fn configure_keys(imgui: &mut ImGui) { } /// Update imgui keyboard state -pub fn handle_keyboard_input(imgui: &mut ImGui, event: KeyboardInput) { +pub fn handle_keyboard_input(imgui: &mut Context, event: KeyboardInput) { handle_modifiers(imgui, event.modifiers); if let Some(key) = event.virtual_keycode { let state_bool = event.state == ElementState::Pressed; @@ -127,7 +127,7 @@ pub fn handle_keyboard_input(imgui: &mut ImGui, event: KeyboardInput) { } /// Update imgui keyboard modifier state -pub fn handle_modifiers(imgui: &mut ImGui, modifiers: ModifiersState) { +pub fn handle_modifiers(imgui: &mut Context, modifiers: ModifiersState) { imgui.set_key_shift(modifiers.shift); imgui.set_key_ctrl(modifiers.ctrl); imgui.set_key_alt(modifiers.alt); @@ -136,7 +136,7 @@ pub fn handle_modifiers(imgui: &mut ImGui, modifiers: ModifiersState) { /// Update imgui mouse wheel position pub fn handle_mouse_scroll_delta( - imgui: &mut ImGui, + imgui: &mut Context, delta: MouseScrollDelta, window_hidpi_factor: f64, app_hidpi_factor: f64, @@ -153,7 +153,7 @@ pub fn handle_mouse_scroll_delta( } /// Update imgui mouse button state -pub fn handle_mouse_button_state(imgui: &mut ImGui, button: MouseButton, state: ElementState) { +pub fn handle_mouse_button_state(imgui: &mut Context, button: MouseButton, state: ElementState) { let mut states = imgui.mouse_down(); let state_bool = state == ElementState::Pressed; match button { @@ -168,7 +168,7 @@ pub fn handle_mouse_button_state(imgui: &mut ImGui, button: MouseButton, state: /// Update imgui state from winit event pub fn handle_event( - imgui: &mut ImGui, + imgui: &mut Context, event: &Event, window_hidpi_factor: f64, app_hidpi_factor: f64, @@ -180,7 +180,7 @@ pub fn handle_event( /// Update imgui state from winit window event pub fn handle_window_event( - imgui: &mut ImGui, + imgui: &mut Context, event: &WindowEvent, window_hidpi_factor: f64, app_hidpi_factor: f64, @@ -223,7 +223,7 @@ pub fn handle_window_event( } /// Update winit window mouse cursor state -pub fn update_mouse_cursor(imgui: &ImGui, window: &Window) { +pub fn update_mouse_cursor(imgui: &Context, window: &Window) { let mouse_cursor = imgui.mouse_cursor(); if imgui.mouse_draw_cursor() || mouse_cursor == ImGuiMouseCursor::None { // Hide OS cursor diff --git a/src/context.rs b/src/context.rs new file mode 100644 index 0000000..a16d290 --- /dev/null +++ b/src/context.rs @@ -0,0 +1,338 @@ +use parking_lot::ReentrantMutex; +use std::cell::RefCell; +use std::ffi::CStr; +use std::ops::Drop; +use std::ptr; +use std::rc::Rc; + +use crate::string::{ImStr, ImString}; +use crate::style::Style; +use crate::sys; +use crate::Ui; + +/// An imgui-rs context. +/// +/// A context needs to be created to access most library functions. Due to current Dear ImGui +/// design choices, at most one active Context can exist at any time. This limitation will likely +/// be removed in a future Dear ImGui version. +/// +/// If you need more than one context, you can use suspended contexts. As long as only one context +/// is active at a time, it's possible to have multiple independent contexts. +/// +/// # Examples +/// +/// Creating a new active context: +/// ``` +/// let ctx = imgui::Context::create(); +/// // ctx is dropped naturally when it goes out of scope, which deactivates and destroys the +/// // context +/// ``` +/// +/// Never try to create an active context when another one is active: +/// +/// ```should_panic +/// let ctx1 = imgui::Context::create(); +/// +/// let ctx2 = imgui::Context::create(); // PANIC +/// ``` +/// +/// Suspending an active context allows you to create another active context: +/// +/// ``` +/// let ctx1 = imgui::Context::create(); +/// let suspended1 = ctx1.suspend(); +/// let ctx2 = imgui::Context::create(); // this is now OK +/// ``` + +#[derive(Debug)] +pub struct Context { + raw: *mut sys::ImGuiContext, + ini_filename: Option, + log_filename: Option, + platform_name: Option, + renderer_name: Option, +} + +lazy_static! { + // This mutex needs to be used to guard all public functions that can affect the underlying + // Dear ImGui active context + static ref CTX_MUTEX: ReentrantMutex<()> = ReentrantMutex::new(()); +} + +fn clear_current_context() { + unsafe { + sys::igSetCurrentContext(ptr::null_mut()); + } +} +fn no_current_context() -> bool { + let ctx = unsafe { sys::igGetCurrentContext() }; + ctx.is_null() +} + +impl Context { + /// Creates a new active imgui-rs context. + /// + /// # Panics + /// + /// Panics if an active context already exists + pub fn create() -> Self { + Self::create_internal() + } + /// Suspends this context so another context can be the active context. + pub fn suspend(self) -> SuspendedContext { + let _guard = CTX_MUTEX.lock(); + assert!( + self.is_current_context(), + "context to be suspended is not the active context" + ); + clear_current_context(); + SuspendedContext(self) + } + pub fn ini_filename(&self) -> Option<&ImStr> { + let io = self.io(); + if io.IniFilename.is_null() { + None + } else { + unsafe { Some(ImStr::from_ptr_unchecked(io.IniFilename)) } + } + } + pub fn set_ini_filename>>(&mut self, ini_filename: T) { + let ini_filename = ini_filename.into(); + self.io_mut().IniFilename = ini_filename + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(ptr::null()); + self.ini_filename = ini_filename; + } + pub fn log_filename(&self) -> Option<&ImStr> { + let io = self.io(); + if io.LogFilename.is_null() { + None + } else { + unsafe { Some(ImStr::from_ptr_unchecked(io.LogFilename)) } + } + } + pub fn set_log_filename>>(&mut self, log_filename: T) { + let log_filename = log_filename.into(); + self.io_mut().LogFilename = log_filename + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(ptr::null()); + self.log_filename = log_filename; + } + pub fn platform_name(&self) -> Option<&ImStr> { + let io = self.io(); + if io.BackendPlatformName.is_null() { + None + } else { + unsafe { Some(ImStr::from_ptr_unchecked(io.BackendPlatformName)) } + } + } + pub fn set_platform_name>>(&mut self, platform_name: T) { + let platform_name = platform_name.into(); + self.io_mut().BackendPlatformName = platform_name + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(ptr::null()); + self.platform_name = platform_name; + } + pub fn renderer_name(&self) -> Option<&ImStr> { + let io = self.io(); + if io.BackendRendererName.is_null() { + None + } else { + unsafe { Some(ImStr::from_ptr_unchecked(io.BackendRendererName)) } + } + } + pub fn set_renderer_name>>(&mut self, renderer_name: T) { + let renderer_name = renderer_name.into(); + self.io_mut().BackendRendererName = renderer_name + .as_ref() + .map(|x| x.as_ptr()) + .unwrap_or(ptr::null()); + self.renderer_name = renderer_name; + } + pub fn load_ini_settings(&mut self, data: &str) { + unsafe { sys::igLoadIniSettingsFromMemory(data.as_ptr() as *const _, data.len()) } + } + pub fn save_ini_settings(&mut self, buf: &mut String) { + let data = unsafe { CStr::from_ptr(sys::igSaveIniSettingsToMemory(ptr::null_mut())) }; + buf.push_str(&data.to_string_lossy()); + } + fn create_internal() -> Self { + let _guard = CTX_MUTEX.lock(); + assert!( + no_current_context(), + "A new active context cannot be created, because another one already exists" + ); + // Dear ImGui implicitly sets the current context during igCreateContext if the current + // context doesn't exist + let raw = unsafe { sys::igCreateContext(ptr::null_mut()) }; + Context { + raw, + ini_filename: None, + log_filename: None, + platform_name: None, + renderer_name: None, + } + } + fn is_current_context(&self) -> bool { + let ctx = unsafe { sys::igGetCurrentContext() }; + self.raw == ctx + } +} + +impl Drop for Context { + fn drop(&mut self) { + let _guard = CTX_MUTEX.lock(); + // If this context is the active context, Dear ImGui automatically deactivates it during + // destruction + unsafe { + sys::igDestroyContext(self.raw); + } + } +} + +/// A suspended imgui-rs context. +/// +/// A suspended context retains its state, but is not usable without activating it first. +/// +/// # Examples +/// +/// Suspended contexts are not directly very useful, but you can activate them: +/// +/// ``` +/// let suspended = imgui::SuspendedContext::create(); +/// match suspended.activate() { +/// Ok(ctx) => { +/// // ctx is now the active context +/// }, +/// Err(suspended) => { +/// // activation failed, so you get the suspended context back +/// } +/// } +/// ``` +#[derive(Debug)] +pub struct SuspendedContext(Context); + +impl SuspendedContext { + /// Creates a new suspended imgui-rs context. + pub fn create() -> Self { + Self::create_internal() + } + /// Attempts to activate this suspended context. + /// + /// If there is no active context, this suspended context is activated and `Ok` is returned, + /// containing the activated context. + /// If there is already an active context, nothing happens and `Err` is returned, containing + /// the original suspended context. + pub fn activate(self) -> Result { + let _guard = CTX_MUTEX.lock(); + if no_current_context() { + unsafe { + sys::igSetCurrentContext(self.0.raw); + } + Ok(self.0) + } else { + Err(self) + } + } + fn create_internal() -> Self { + let _guard = CTX_MUTEX.lock(); + let raw = unsafe { sys::igCreateContext(ptr::null_mut()) }; + let ctx = Context { + raw, + ini_filename: None, + log_filename: None, + platform_name: None, + renderer_name: None, + }; + if ctx.is_current_context() { + // Oops, the context was activated -> deactivate + clear_current_context(); + } + SuspendedContext(ctx) + } +} + +#[test] +fn test_one_context() { + let _guard = crate::test::TEST_MUTEX.lock(); + let _ctx = Context::create(); + assert!(!no_current_context()); +} + +#[test] +fn test_drop_clears_current_context() { + let _guard = crate::test::TEST_MUTEX.lock(); + { + let _ctx1 = Context::create(); + assert!(!no_current_context()); + } + assert!(no_current_context()); + { + let _ctx2 = Context::create(); + assert!(!no_current_context()); + } + assert!(no_current_context()); +} + +#[test] +fn test_new_suspended() { + let _guard = crate::test::TEST_MUTEX.lock(); + let ctx = Context::create(); + let _suspended = SuspendedContext::create(); + assert!(ctx.is_current_context()); + ::std::mem::drop(_suspended); + assert!(ctx.is_current_context()); +} + +#[test] +fn test_suspend() { + let _guard = crate::test::TEST_MUTEX.lock(); + let ctx = Context::create(); + assert!(!no_current_context()); + let _suspended = ctx.suspend(); + assert!(no_current_context()); + let _ctx2 = Context::create(); +} + +#[test] +fn test_drop_suspended() { + let _guard = crate::test::TEST_MUTEX.lock(); + let suspended = Context::create().suspend(); + assert!(no_current_context()); + let ctx2 = Context::create(); + ::std::mem::drop(suspended); + assert!(ctx2.is_current_context()); +} + +#[test] +fn test_suspend_activate() { + let _guard = crate::test::TEST_MUTEX.lock(); + let suspended = Context::create().suspend(); + assert!(no_current_context()); + let ctx = suspended.activate().unwrap(); + assert!(ctx.is_current_context()); +} + +#[test] +fn test_suspend_failure() { + let _guard = crate::test::TEST_MUTEX.lock(); + let suspended = Context::create().suspend(); + let _ctx = Context::create(); + assert!(suspended.activate().is_err()); +} + +#[test] +fn test_ini_load_save() { + let (_guard, mut ctx) = crate::test::test_ctx(); + let data = "[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0"; + ctx.load_ini_settings(&data); + let mut buf = String::new(); + ctx.save_ini_settings(&mut buf); + assert_eq!(data.trim(), buf.trim()); +} diff --git a/src/lib.rs b/src/lib.rs index a369ec3..67f36a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ pub extern crate imgui_sys as sys; +#[macro_use] +extern crate lazy_static; use std::ffi::CStr; use std::mem; @@ -13,6 +15,7 @@ pub use self::color_editors::{ ColorButton, ColorEdit, ColorEditMode, ColorFormat, ColorPicker, ColorPickerMode, ColorPreview, EditableColor, }; +pub use self::context::*; pub use self::drag::{ DragFloat, DragFloat2, DragFloat3, DragFloat4, DragFloatRange2, DragInt, DragInt2, DragInt3, DragInt4, DragIntRange2, @@ -46,6 +49,7 @@ use internal::RawCast; mod child_frame; mod color_editors; +mod context; mod drag; mod fonts; mod image; @@ -59,17 +63,12 @@ mod progressbar; mod sliders; mod string; mod style; +#[cfg(test)] +mod test; mod trees; mod window; mod window_draw_list; -pub struct ImGui { - // We need to keep ownership of the ImStr values to ensure the *const char pointer - // lives long enough in case the ImStr contains a Cow::Owned - ini_filename: Option, - log_filename: Option, -} - pub struct TextureHandle<'a> { pub width: u32, pub height: u32, @@ -108,16 +107,7 @@ impl FrameSize { } } -impl ImGui { - pub fn init() -> ImGui { - unsafe { - sys::igCreateContext(ptr::null_mut()); - } - ImGui { - ini_filename: None, - log_filename: None, - } - } +impl Context { fn io(&self) -> &sys::ImGuiIO { unsafe { &*sys::igGetIO() } } @@ -160,26 +150,6 @@ impl ImGui { pub fn set_font_texture_id(&mut self, value: ImTexture) { self.fonts().set_texture_id(value.id()); } - pub fn set_ini_filename(&mut self, value: Option) { - { - let io = self.io_mut(); - io.IniFilename = match value { - Some(ref x) => x.as_ptr(), - None => ptr::null(), - } - } - self.ini_filename = value; - } - pub fn set_log_filename(&mut self, value: Option) { - { - let io = self.io_mut(); - io.LogFilename = match value { - Some(ref x) => x.as_ptr(), - None => ptr::null(), - } - } - self.log_filename = value; - } pub fn set_ini_saving_rate(&mut self, value: f32) { let io = self.io_mut(); io.IniSavingRate = value; @@ -391,31 +361,14 @@ impl ImGui { } unsafe { sys::igNewFrame(); - CURRENT_UI = Some(Ui { - imgui: mem::transmute(self as &'a ImGui), - frame_size, - needs_cleanup: false, - }); } Ui { imgui: self, frame_size, - needs_cleanup: true, } } } -impl Drop for ImGui { - fn drop(&mut self) { - unsafe { - CURRENT_UI = None; - sys::igDestroyContext(ptr::null_mut()); - } - } -} - -static mut CURRENT_UI: Option> = None; - pub struct DrawData<'a> { raw: &'a mut sys::ImDrawData, } @@ -493,9 +446,8 @@ pub struct DrawList<'a> { } pub struct Ui<'ui> { - imgui: &'ui ImGui, + imgui: &'ui Context, frame_size: FrameSize, - needs_cleanup: bool, } static FMT: &'static [u8] = b"%s\0"; @@ -508,7 +460,7 @@ impl<'ui> Ui<'ui> { pub fn frame_size(&self) -> FrameSize { self.frame_size } - pub fn imgui(&self) -> &ImGui { + pub fn imgui(&self) -> &Context { self.imgui } pub fn want_capture_mouse(&self) -> bool { @@ -579,21 +531,14 @@ impl<'ui> Ui<'ui> { impl<'a> Drop for Ui<'a> { fn drop(&mut self) { - if self.needs_cleanup && !thread::panicking() { + if !thread::panicking() { unsafe { sys::igEndFrame(); - CURRENT_UI = None; } } } } -impl<'a> Ui<'a> { - pub unsafe fn current_ui() -> Option<&'a Ui<'a>> { - CURRENT_UI.as_ref() - } -} - // Window impl<'ui> Ui<'ui> { pub fn window<'p>(&self, name: &'p ImStr) -> Window<'ui, 'p> { @@ -1222,7 +1167,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// if ui.button(im_str!("Show modal"), (0.0, 0.0)) { /// ui.open_popup(im_str!("modal")); @@ -1302,7 +1247,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// # let mut selected_radio_value = 2; /// ui.radio_button(im_str!("Item 1"), &mut selected_radio_value, 1); @@ -1319,7 +1264,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// # let mut radio_button_test = "cats".to_string(); /// if ui.radio_button_bool(im_str!("Cats"), radio_button_test == "cats") { @@ -1412,7 +1357,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// ui.progress_bar(0.6) /// .size((100.0, 12.0)) @@ -1430,7 +1375,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// ui.window(im_str!("ChatWindow")) /// .title_bar(true) @@ -1460,7 +1405,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// ui.with_style_var(StyleVar::Alpha(0.2), || { /// ui.text(im_str!("AB")); @@ -1478,7 +1423,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// # let styles = [StyleVar::Alpha(0.2), StyleVar::WindowPadding([1.0, 1.0])]; /// ui.with_style_vars(&styles, || { @@ -1578,7 +1523,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// ui.with_color_var(StyleColor::Text, [1.0, 0.0, 0.0, 1.0], || { /// ui.text_wrapped(im_str!("AB")); @@ -1604,7 +1549,7 @@ impl<'ui> Ui<'ui> { /// # Example /// ```rust,no_run /// # use imgui::*; - /// # let mut imgui = ImGui::init(); + /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(FrameSize::new(100.0, 100.0, 1.0), 0.1); /// let red = [1.0, 0.0, 0.0, 1.0]; /// let green = [0.0, 1.0, 0.0, 1.0]; diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..25c3bbe --- /dev/null +++ b/src/test.rs @@ -0,0 +1,15 @@ +use parking_lot::{ReentrantMutex, ReentrantMutexGuard}; +use std::ptr; + +use crate::context::Context; + +lazy_static! { + pub static ref TEST_MUTEX: ReentrantMutex<()> = ReentrantMutex::new(()); +} + +pub fn test_ctx() -> (ReentrantMutexGuard<'static, ()>, Context) { + let guard = TEST_MUTEX.lock(); + let mut ctx = Context::create(); + ctx.io_mut().IniFilename = ptr::null(); + (guard, ctx) +}