mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 05:28:35 +00:00
Pull first part of 0.1 context API
This commit is contained in:
parent
f7f9deb321
commit
9516e622be
@ -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"
|
||||
|
||||
2
imgui-examples/Cargo.lock
generated
2
imgui-examples/Cargo.lock
generated
@ -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]]
|
||||
|
||||
@ -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<F: FnMut(&Ui) -> 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] {
|
||||
|
||||
@ -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<T> = Result<T, RendererError>;
|
||||
|
||||
@ -190,7 +190,7 @@ pub struct Renderer<R: Resources> {
|
||||
|
||||
impl<R: Resources> Renderer<R> {
|
||||
pub fn init<F: Factory<R>>(
|
||||
imgui: &mut ImGui,
|
||||
imgui: &mut Context,
|
||||
factory: &mut F,
|
||||
shaders: Shaders,
|
||||
out: RenderTargetView<R, gfx::format::Rgba8>,
|
||||
|
||||
2
imgui-glium-examples/Cargo.lock
generated
2
imgui-glium-examples/Cargo.lock
generated
@ -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]]
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<F: Facade>(imgui: &mut ImGui, ctx: &F) -> RendererResult<Renderer> {
|
||||
pub fn init<F: Facade>(imgui: &mut imgui::Context, ctx: &F) -> RendererResult<Renderer> {
|
||||
let device_objects = DeviceObjects::init(imgui, ctx)?;
|
||||
Ok(Renderer {
|
||||
ctx: Rc::clone(ctx.get_context()),
|
||||
@ -222,7 +222,7 @@ fn compile_default_program<F: Facade>(
|
||||
}
|
||||
|
||||
impl DeviceObjects {
|
||||
pub fn init<F: Facade>(im_gui: &mut ImGui, ctx: &F) -> RendererResult<DeviceObjects> {
|
||||
pub fn init<F: Facade>(im_gui: &mut imgui::Context, ctx: &F) -> RendererResult<DeviceObjects> {
|
||||
use glium::texture::{ClientFormat, RawImage2d};
|
||||
|
||||
let program = compile_default_program(ctx)?;
|
||||
|
||||
@ -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
|
||||
|
||||
338
src/context.rs
Normal file
338
src/context.rs
Normal file
@ -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<ImString>,
|
||||
log_filename: Option<ImString>,
|
||||
platform_name: Option<ImString>,
|
||||
renderer_name: Option<ImString>,
|
||||
}
|
||||
|
||||
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<T: Into<Option<ImString>>>(&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<T: Into<Option<ImString>>>(&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<T: Into<Option<ImString>>>(&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<T: Into<Option<ImString>>>(&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<Context, SuspendedContext> {
|
||||
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());
|
||||
}
|
||||
93
src/lib.rs
93
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<ImString>,
|
||||
log_filename: Option<ImString>,
|
||||
}
|
||||
|
||||
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<ImString>) {
|
||||
{
|
||||
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<ImString>) {
|
||||
{
|
||||
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<Ui<'static>> = 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];
|
||||
|
||||
15
src/test.rs
Normal file
15
src/test.rs
Normal file
@ -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)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user