#![cfg_attr(test, allow(clippy::float_cmp))] #![deny(rust_2018_idioms)] // #![deny(missing_docs)] pub extern crate imgui_sys as sys; use std::cell; use std::os::raw::{c_char, c_void}; pub use self::clipboard::*; pub use self::color::ImColor32; pub use self::context::*; pub use self::drag_drop::{DragDropFlags, DragDropSource, DragDropTarget}; pub use self::draw_list::{ChannelsSplit, DrawListMut}; pub use self::fonts::atlas::*; pub use self::fonts::font::*; pub use self::fonts::glyph::*; pub use self::fonts::glyph_ranges::*; pub use self::input::keyboard::*; pub use self::input::mouse::*; pub use self::input_widget::*; pub use self::io::*; pub use self::layout::*; pub use self::list_clipper::ListClipper; pub use self::plothistogram::PlotHistogram; pub use self::plotlines::PlotLines; pub use self::popups::*; pub use self::render::draw_data::*; pub use self::render::renderer::*; pub use self::stacks::*; pub use self::string::*; pub use self::style::*; #[cfg(feature = "tables-api")] pub use self::tables::*; pub use self::utils::*; pub use self::widget::color_editors::*; pub use self::widget::combo_box::*; pub use self::widget::drag::*; pub use self::widget::image::*; pub use self::widget::list_box::*; pub use self::widget::menu::*; pub use self::widget::misc::*; pub use self::widget::progress_bar::*; pub use self::widget::selectable::*; pub use self::widget::slider::*; pub use self::widget::tab::*; pub use self::widget::tree::*; pub use self::window::child_window::*; pub use self::window::*; use internal::RawCast; use math::*; #[macro_use] mod string; #[macro_use] mod tokens; mod clipboard; pub mod color; mod columns; mod context; pub mod drag_drop; pub mod draw_list; mod fonts; mod input; mod input_widget; pub mod internal; mod io; mod layout; mod list_clipper; mod math; mod plothistogram; mod plotlines; mod popups; mod render; mod stacks; mod style; #[cfg(feature = "tables-api")] mod tables; #[cfg(test)] mod test; mod utils; mod widget; mod window; // Used by macros. Underscores are just to make it clear it's not part of the // public API. #[doc(hidden)] pub use core as __core; /// Returns the underlying Dear ImGui library version #[doc(alias = "GetVersion")] pub fn dear_imgui_version() -> &'static str { unsafe { let bytes = std::ffi::CStr::from_ptr(sys::igGetVersion()).to_bytes(); std::str::from_utf8_unchecked(bytes) } } impl Context { /// Returns the global imgui-rs time. /// /// Incremented by Io::delta_time every frame. #[doc(alias = "GetTime")] pub fn time(&self) -> f64 { unsafe { sys::igGetTime() } } /// Returns the global imgui-rs frame count. /// /// Incremented by 1 every frame. #[doc(alias = "GetFrameCount")] pub fn frame_count(&self) -> i32 { unsafe { sys::igGetFrameCount() } } } /// A reference for building the user interface for one frame #[derive(Debug)] pub struct Ui { /// our scratch sheet buffer: cell::UnsafeCell, } 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 { let handle = &mut *self.buffer.get(); handle.scratch_txt(txt) } } /// Internal method to push an option text to our scratch buffer. fn scratch_txt_opt(&self, txt: Option>) -> *const sys::cty::c_char { unsafe { let handle = &mut *self.buffer.get(); handle.scratch_txt_opt(txt) } } fn scratch_txt_two( &self, txt_0: impl AsRef, txt_1: impl AsRef, ) -> (*const sys::cty::c_char, *const sys::cty::c_char) { unsafe { let handle = &mut *self.buffer.get(); handle.scratch_txt_two(txt_0, txt_1) } } fn scratch_txt_with_opt( &self, txt_0: impl AsRef, txt_1: Option>, ) -> (*const sys::cty::c_char, *const sys::cty::c_char) { unsafe { let handle = &mut *self.buffer.get(); handle.scratch_txt_with_opt(txt_0, txt_1) } } /// Returns an immutable reference to the inputs/outputs object #[doc(alias = "GetIO")] pub fn io(&self) -> &Io { unsafe { &*(sys::igGetIO() as *const Io) } } /// 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 { unsafe { *self.style() } } /// 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 { /// Renders a demo window (previously called a test window), which demonstrates most /// Dear Imgui features. #[doc(alias = "ShowDemoWindow")] pub fn show_demo_window(&self, opened: &mut bool) { unsafe { sys::igShowDemoWindow(opened); } } /// Renders an about window. /// /// Displays the Dear ImGui version/credits, and build/system information. #[doc(alias = "ShowAboutWindow")] pub fn show_about_window(&self, opened: &mut bool) { unsafe { sys::igShowAboutWindow(opened); } } /// Renders a metrics/debug window. /// /// Displays Dear ImGui internals: draw commands (with individual draw calls and vertices), /// window list, basic internal state, etc. #[doc(alias = "ShowMetricsWindow")] pub fn show_metrics_window(&self, opened: &mut bool) { unsafe { sys::igShowMetricsWindow(opened); } } /// Renders a style editor block (not a window) for the given `Style` structure #[doc(alias = "ShowStyleEditor")] pub fn show_style_editor(&self, style: &mut Style) { unsafe { sys::igShowStyleEditor(style.raw_mut()); } } /// Renders a style editor block (not a window) for the currently active style #[doc(alias = "ShowStyleEditor")] pub fn show_default_style_editor(&self) { unsafe { sys::igShowStyleEditor(std::ptr::null_mut()) }; } /// Renders a basic help/info block (not a window) #[doc(alias = "ShowUserGuide")] pub fn show_user_guide(&self) { unsafe { sys::igShowUserGuide() }; } } /// Unique ID used by widgets #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Id<'a> { Int(i32), Str(&'a str), Ptr(*const c_void), } impl From for Id<'static> { #[inline] fn from(i: i32) -> Self { Id::Int(i) } } impl<'a, T: ?Sized + AsRef> From<&'a T> for Id<'a> { #[inline] fn from(s: &'a T) -> Self { Id::Str(s.as_ref()) } } impl From<*const T> for Id<'static> { #[inline] fn from(p: *const T) -> Self { Id::Ptr(p as *const c_void) } } impl From<*mut T> for Id<'static> { #[inline] fn from(p: *mut T) -> Self { Id::Ptr(p as *const T as *const c_void) } } impl<'a> Id<'a> { // this is used in the tables-api and possibly elsewhere, // but not with just default features... #[allow(dead_code)] fn as_imgui_id(&self) -> sys::ImGuiID { unsafe { match self { Id::Ptr(p) => sys::igGetID_Ptr(*p), Id::Str(s) => { let s1 = s.as_ptr() as *const std::os::raw::c_char; let s2 = s1.add(s.len()); sys::igGetID_StrStr(s1, s2) } Id::Int(i) => { let p = *i as *const std::os::raw::c_void; sys::igGetID_Ptr(p) } // Id::ImGuiID(n) => *n, } } } } impl<'a> Default for Id<'a> { fn default() -> Self { Self::Int(0) } } impl Ui { /// # Windows /// Start constructing a window. /// /// This, like many objects in the library, uses the builder /// pattern to set optional arguments (like window size, flags, /// etc). Once all desired options are set, you must call either /// [`Window::build`] or [`Window::begin`] must be called to /// actually create the window. /// /// # Examples /// /// Create a window using the closure based [`Window::build`]: /// ```no_run /// # let mut ctx = imgui::Context::create(); /// # let ui = ctx.frame(); /// ui.window("Example Window") /// .size([100.0, 50.0], imgui::Condition::FirstUseEver) /// .build(|| { /// ui.text("An example"); /// }); /// ``` pub fn window>(&self, name: Label) -> Window<'_, '_, Label> { Window::new(self, name) } /// Same as [`Ui::window`] but using the "token based" `.begin()` approach. /// /// ``` /// fn example(ui: &imgui::Ui) { /// let wt = ui.window("Example Window") /// .size([100.0, 50.0], imgui::Condition::FirstUseEver) /// .begin(); /// if wt.is_some() { /// ui.text("Window is visible"); /// } /// // Window ends where where wt is dropped, /// // or you could call /// wt.unwrap().end() /// } /// ``` pub fn child_window>(&self, name: Label) -> ChildWindow<'_, Label> { ChildWindow::new(self, name) } } // Widgets: Input impl<'ui> Ui { #[doc(alias = "InputText", alias = "InputTextWithHint")] pub fn input_text<'p, L: AsRef>( &'ui self, label: L, buf: &'p mut String, ) -> InputText<'ui, 'p, L> { InputText::new(self, label, buf) } #[doc(alias = "InputText", alias = "InputTextMultiline")] pub fn input_text_multiline<'p, L: AsRef>( &'ui self, label: L, buf: &'p mut String, size: [f32; 2], ) -> InputTextMultiline<'ui, 'p, L> { InputTextMultiline::new(self, label, buf, size) } #[doc(alias = "InputFloat2")] pub fn input_float<'p, L: AsRef>( &'ui self, label: L, value: &'p mut f32, ) -> InputFloat<'ui, 'p, L> { InputFloat::new(self, label, value) } #[doc(alias = "InputFloat2")] pub fn input_float2<'p, L, T>( &'ui self, label: L, value: &'p mut T, ) -> InputFloat2<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintVec2: Into + Into<[f32; 2]>, { InputFloat2::new(self, label, value) } #[doc(alias = "InputFloat3")] pub fn input_float3<'p, L, T>( &'ui self, label: L, value: &'p mut T, ) -> InputFloat3<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintVec3: Into + Into<[f32; 3]>, { InputFloat3::new(self, label, value) } #[doc(alias = "InputFloat4")] pub fn input_float4<'p, L, T>( &'ui self, label: L, value: &'p mut T, ) -> InputFloat4<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintVec4: Into + Into<[f32; 4]>, { InputFloat4::new(self, label, value) } #[doc(alias = "InputInt")] pub fn input_int<'p, L: AsRef>( &'ui self, label: L, value: &'p mut i32, ) -> InputInt<'ui, 'p, L> { InputInt::new(self, label, value) } #[doc(alias = "InputInt2")] pub fn input_int2<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt2<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintIVec2: Into + Into<[i32; 2]>, { InputInt2::new(self, label, value) } #[doc(alias = "InputInt3")] pub fn input_int3<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt3<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintIVec3: Into + Into<[i32; 3]>, { InputInt3::new(self, label, value) } #[doc(alias = "InputInt4")] pub fn input_int4<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt4<'ui, 'p, L, T> where L: AsRef, T: Copy + Into, MintIVec4: Into + Into<[i32; 4]>, { InputInt4::new(self, label, value) } } create_token!( /// Tracks a layout tooltip that can be ended by calling `.end()` or by dropping. pub struct TooltipToken<'ui>; /// Drops the layout tooltip manually. You can also just allow this token /// to drop on its own. drop { sys::igEndTooltip() } ); /// # Tooltips 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. /// /// # Examples /// /// ``` /// # use imgui::*; /// fn user_interface(ui: &Ui) { /// ui.text("Hover over me"); /// if ui.is_item_hovered() { /// ui.tooltip(|| { /// ui.text_colored([1.0, 0.0, 0.0, 1.0], im_str!("I'm red!")); /// }); /// } /// } /// ``` #[doc(alias = "BeginTooltip", alias = "EndTootip")] pub fn tooltip(&self, f: F) { unsafe { sys::igBeginTooltip() }; f(); unsafe { sys::igEndTooltip() }; } /// Construct a tooltip window that can have any kind of content. /// /// Returns a `TooltipToken` that must be ended by calling `.end()` #[doc(alias = "BeginTooltip")] pub fn begin_tooltip(&self) -> TooltipToken<'_> { unsafe { sys::igBeginTooltip() }; TooltipToken::new(self) } /// Construct a tooltip window with simple text content. /// /// Typically used with `Ui::is_item_hovered()` or some other conditional check. /// /// # Examples /// /// ``` /// # use imgui::*; /// fn user_interface(ui: &Ui) { /// ui.text("Hover over me"); /// if ui.is_item_hovered() { /// ui.tooltip_text("I'm a tooltip!"); /// } /// } /// ``` #[doc(alias = "BeginTooltip", alias = "EndTootip")] pub fn tooltip_text>(&self, text: T) { self.tooltip(|| self.text(text)); } } create_token!( /// Starts a scope where interaction is disabled. Ends be calling `.end()` or when the token is dropped. pub struct DisabledToken<'ui>; /// Drops the layout tooltip manually. You can also just allow this token /// to drop on its own. drop { sys::igEndDisabled() } ); /// # Disabling widgets /// /// 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 { /// Creates a scope where interactions are disabled. /// /// Scope ends when returned token is dropped, or `.end()` is /// explicitly called /// /// # Examples /// /// ``` /// # use imgui::*; /// fn user_interface(ui: &Ui) { /// let disable_buttons = true; /// let _d = ui.begin_disabled(disable_buttons); /// ui.button(im_str!("Dangerous button")); /// } /// ``` #[doc(alias = "BeginDisabled")] pub fn begin_disabled(&self, disabled: bool) -> DisabledToken<'_> { unsafe { sys::igBeginDisabled(disabled) }; DisabledToken::new(self) } /// Identical to [`Ui::begin_disabled`] but exists to allow avoiding a /// double-negative, for example `begin_enabled(enable_buttons)` /// instead of `begin_disabled(!enable_buttons)`) #[doc(alias = "BeginDisabled")] pub fn begin_enabled(&self, enabled: bool) -> DisabledToken<'_> { self.begin_disabled(!enabled) } /// Helper to create a disabled section of widgets /// /// # Examples /// /// ``` /// # use imgui::*; /// fn user_interface(ui: &Ui) { /// let safe_mode = true; /// ui.disabled(safe_mode, || { /// ui.button(im_str!("Dangerous button")); /// }); /// } /// ``` #[doc(alias = "BeginDisabled", alias = "EndDisabled")] pub fn disabled(&self, disabled: bool, f: F) { unsafe { sys::igBeginDisabled(disabled) }; f(); unsafe { sys::igEndDisabled() }; } /// Same as [`Ui::disabled`] but with logic reversed. See /// [`Ui::begin_enabled`]. #[doc(alias = "BeginDisabled", alias = "EndDisabled")] pub fn enabled(&self, enabled: bool, f: F) { unsafe { sys::igBeginDisabled(!enabled) }; f(); unsafe { sys::igEndDisabled() }; } } // Widgets: ListBox impl Ui { #[doc(alias = "ListBox")] pub fn list_box<'p, StringType: AsRef + ?Sized>( &self, label: impl AsRef, current_item: &mut i32, items: &'p [&'p StringType], height_in_items: i32, ) -> bool { let (label_ptr, items_inner) = unsafe { let handle = &mut *self.scratch_buffer().get(); handle.refresh_buffer(); let label_ptr = handle.push(label); let items_inner: Vec<_> = items.iter().map(|&v| handle.push(v)).collect(); (label_ptr, items_inner) }; unsafe { sys::igListBox_Str_arr( label_ptr, current_item, items_inner.as_ptr() as *mut *const c_char, items_inner.len() as i32, height_in_items, ) } } // written out for the future times... // #[doc(alias = "ListBox")] // pub fn list_box_const<'p, StringType: AsRef + ?Sized, const N: usize>( // &self, // label: impl AsRef, // current_item: &mut i32, // items: [&'p StringType; N], // height_in_items: i32, // ) -> bool { // let (label_ptr, items_inner) = unsafe { // let handle = &mut *self.buffer.get(); // handle.refresh_buffer(); // let label_ptr = handle.push(label); // let mut items_inner: [*const i8; N] = [std::ptr::null(); N]; // for (i, item) in items.iter().enumerate() { // items_inner[i] = handle.push(item); // } // (label_ptr, items_inner) // }; // unsafe { // sys::igListBoxStr_arr( // label_ptr, // current_item, // items_inner.as_ptr() as *mut *const c_char, // items_inner.len() as i32, // height_in_items, // ) // } // } } impl<'ui> Ui { #[doc(alias = "PlotLines")] pub fn plot_lines<'p, Label: AsRef>( &'ui self, label: Label, values: &'p [f32], ) -> PlotLines<'ui, 'p, Label> { PlotLines::new(self, label, values) } #[doc(alias = "PlotHistogram")] pub fn plot_histogram<'p, Label: AsRef>( &'ui self, label: Label, values: &'p [f32], ) -> PlotHistogram<'ui, 'p, Label> { PlotHistogram::new(self, label, values) } /// 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) /// with `hide_text_after_double_hash` set to false and `wrap_width` set to `-1.0`. #[doc(alias = "CalcTextSize")] pub fn calc_text_size>(&self, text: T) -> [f32; 2] { self.calc_text_size_with_opts(text, false, -1.0) } /// Calculate the size required for a given text string. /// /// hide_text_after_double_hash allows the user to insert comments into their text, using a double hash-tag prefix. /// This is a feature of imgui. /// /// wrap_width allows you to request a width at which to wrap the text to a newline for the calculation. #[doc(alias = "CalcTextSize")] pub fn calc_text_size_with_opts>( &self, text: T, hide_text_after_double_hash: bool, wrap_width: f32, ) -> [f32; 2] { let mut out = sys::ImVec2::zero(); let text = text.as_ref(); unsafe { let start = text.as_ptr(); let end = start.add(text.len()); sys::igCalcTextSize( &mut out, start as *const c_char, end as *const c_char, hide_text_after_double_hash, wrap_width, ) }; out.into() } } /// # Draw list for custom drawing impl Ui { /// Get access to drawing API /// /// # Examples /// /// ```rust,no_run /// # use imgui::*; /// fn custom_draw(ui: &Ui) { /// let draw_list = ui.get_window_draw_list(); /// // Draw a line /// const WHITE: [f32; 3] = [1.0, 1.0, 1.0]; /// draw_list.add_line([100.0, 100.0], [200.0, 200.0], WHITE).build(); /// // Continue drawing ... /// } /// ``` /// /// This function will panic if several instances of [`DrawListMut`] /// coexist. Before a new instance is got, a previous instance should be /// dropped. /// /// ```rust /// # use imgui::*; /// fn custom_draw(ui: &Ui) { /// let draw_list = ui.get_window_draw_list(); /// // Draw something... /// /// // This second call will panic! /// let draw_list = ui.get_window_draw_list(); /// } /// ``` #[must_use] #[doc(alias = "GetWindowDrawList")] pub fn get_window_draw_list(&self) -> DrawListMut<'_> { DrawListMut::window(self) } #[must_use] #[doc(alias = "GetBackgroundDrawList")] pub fn get_background_draw_list(&self) -> DrawListMut<'_> { DrawListMut::background(self) } #[must_use] #[doc(alias = "GetForegroundDrawList")] pub fn get_foreground_draw_list(&self) -> DrawListMut<'_> { DrawListMut::foreground(self) } } /// Condition for applying a setting #[repr(i8)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Condition { /// Never apply the setting Never = -1, /// Apply the setting every frame Always = sys::ImGuiCond_Always as i8, /// Apply the setting once per runtime session (only the first /// call will succeed). Will ignore any setting saved in `.ini` Once = sys::ImGuiCond_Once as i8, /// Apply the setting if the object/window has no persistently /// saved data (but otherwise use the setting from the .ini file) FirstUseEver = sys::ImGuiCond_FirstUseEver as i8, /// Apply the setting if the object/window is appearing after /// being hidden/inactive (or the first time) Appearing = sys::ImGuiCond_Appearing as i8, } /// A cardinal direction #[repr(i32)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Direction { None = sys::ImGuiDir_None, Left = sys::ImGuiDir_Left, Right = sys::ImGuiDir_Right, Up = sys::ImGuiDir_Up, Down = sys::ImGuiDir_Down, }