imgui-rs/imgui/src/lib.rs
2024-10-02 08:48:59 -04:00

1034 lines
33 KiB
Rust

//! `imgui-rs` are the Rust bindings to [Dear ImGui](https://github.com/ocornut/imgui), the standard,
//! battle-tested, immediate mode user-interface library. Although Dear ImGui and `imgui-rs` are under
//! active development, Dear ImGui is extremely production ready, having been used across the software
//! industry to ship small and massive projects.
//!
//! ## Hello World
//!
//! ```no_run
//! # fn render_ui(ui: &mut imgui::Ui) {
//! ui.window("Hello world")
//! .size([300.0, 100.0], imgui::Condition::FirstUseEver)
//! .build(|| {
//! ui.text("Hello world!");
//! ui.text("こんにちは世界!");
//! ui.text("This...is...imgui-rs!");
//! ui.separator();
//! let mouse_pos = ui.io().mouse_pos;
//! ui.text(format!(
//! "Mouse Position: ({:.1},{:.1})",
//! mouse_pos[0], mouse_pos[1]
//! ));
//! });
//! # }
//!```
//! ## Features
//!
//! - Bindings for Dear ImGui that can be used with safe Rust. Note: API coverage
//! is not 100%, but will keep improving over time.
//! - Builder structs for use cases where the original C++ library uses optional
//! function parameters
//! - Easy integration with `glow` and community integrations with `wgpu` and `glium`
//! - Easy integration with `winit` and `sdl2`
//! - Optional support for the freetype font rasterizer and the docking branch
//!
//! ## Getting Started
//!
//! Almost every application that uses imgui-rs needs two additional components in
//! addition to the main `imgui` crate: a **backend platform**, and a **renderer**.
//!
//! **imgui-rs is not tied to any particular renderer or platform.**
//!
//! ### Backend Platform
//!
//! The backend platform is responsible for integrating imgui-rs with the operating
//! system and its window management. Its responsibilities include the following:
//!
//! - Handling input events (e.g. keyboard, mouse) and updating imgui-rs state
//! accordingly
//! - Passing information about the OS window (e.g. size, DPI factor) to imgui-rs
//! - Updating the OS-side mouse cursor when imgui-rs requests it
//!
//! We provide the following backends:
//! - [`imgui-winit-support`](https://github.com/imgui-rs/imgui-winit-support)
//! - [`imgui-sdl2-support`](https://github.com/imgui-rs/imgui-sdl2-support)
//!
//! You can also write your own support code if you have a more advanced use case,
//! because **imgui-rs is not tied to any specific graphics / OS API**.
//!
//! ### Renderer
//!
//! The renderer is responsible for taking generic, renderer-agnostic `draw lists`
//! generated by `imgui-rs`, and rendering them using some graphics API. Its
//! responsibilities include the following:
//!
//! - Rendering using vertex/index buffers and command lists
//! - Handling of DPI factors and scissor rects
//! - Texture management
//!
//! We provide the following renderer as an official source (ie, it will always be up to date and working):
//! - [`imgui-glow-renderer`](https://github.com/imgui-rs/imgui-glow-renderer)
//!
//! Additionally, there are other libraries which provide other kinds of renderers,
//! which may be out of date with `imgui-rs` releases, but might work well for your use case:
//!
//! 1. [`imgui-wgpu`](https://github.com/Yatekii/imgui-wgpu-rs)
//! 2. [`imgui-d3d12-renderer`](https://github.com/curldivergence/imgui-d3d12-renderer)
//! 3. [`imgui-dx11-renderer`](https://github.com/veykril/imgui-dx11-renderer)
//! 4. [`imgui-gfx-renderer`](https://github.com/imgui-rs/imgui-gfx-renderer): Deprecated (no longer maintained beyond imgui-rs v0.8). Renderer implementation that uses the `gfx` crate (_not the new gfx-hal crate_)
//! 5. [`imgui-glium-renderer`](https://github.com/imgui-rs/imgui-glium-renderer): Deprecated implementation that uses the `glium` crate
//! 6. Many more can be found on [crates.io](https://crates.io) either using search or the ["dependents" page](https://crates.io/crates/imgui/reverse_dependencies) (the "depends on" text indicates if the crate has been updated for current versions of imgui-rs)
//!
//! You can also write your own support code if you have a more advanced use case, because **imgui-rs is not tied to any specific graphics / OS API**.
#![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;
pub use self::clipboard::*;
pub use self::color::ImColor32;
pub use self::context::*;
#[cfg(feature = "docking")]
pub use self::docking_utils::*;
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::platform_io::*;
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::text_filter::*;
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;
#[cfg(feature = "docking")]
mod dock_space;
#[cfg(feature = "docking")]
mod docking_utils;
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 platform_io;
mod plothistogram;
mod plotlines;
mod popups;
mod render;
mod stacks;
mod style;
#[cfg(feature = "tables-api")]
mod tables;
#[cfg(test)]
mod test;
pub mod text_filter;
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<string::UiBuffer>,
}
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<string::UiBuffer> {
&self.buffer
}
/// Internal method to push a single text to our scratch buffer.
fn scratch_txt(&self, txt: impl AsRef<str>) -> *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<impl AsRef<str>>) -> *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<str>,
txt_1: impl AsRef<str>,
) -> (*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<str>,
txt_1: Option<impl AsRef<str>>,
) -> (*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`].
///
/// [`end_frame_early`]: Self::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.
///
/// This represents a hash of the current stack of Ids used in ImGui + the
/// input provided. It is only used in a few places directly in the
/// codebase, but you can think of it as effectively allowing you to
/// run your Id hashing yourself. More often [`Ui::push_id`] and the likes
/// are used instead.
///
/// Previously, in v0.7, this was erroneously constructed with `From`
/// implementations. Now, however, it is made from the `Ui` object
/// directly, with a few deprecated helper methods here.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash)]
pub struct Id(pub(crate) u32);
impl Id {
#[deprecated(since = "0.8.0", note = "Use ui.new_id_int(...)")]
#[allow(non_snake_case)]
pub fn Int(input: i32, ui: &Ui) -> Self {
ui.new_id_int(input)
}
#[deprecated(since = "0.8.0", note = "Use ui.new_id_str(...)")]
#[allow(non_snake_case)]
pub fn Str(input: impl AsRef<str>, ui: &Ui) -> Self {
ui.new_id_str(input)
}
#[deprecated(since = "0.8.0", note = "Use ui.new_id_ptr(...)")]
#[allow(non_snake_case)]
pub fn Ptr<T>(input: &T, ui: &Ui) -> Self {
ui.new_id_ptr(input)
}
}
impl Ui {
/// Create new [`Id`] from a `usize`. See [`Id`] for details.
pub fn new_id(&self, input: usize) -> Id {
let p = input as *const std::os::raw::c_void;
let value = unsafe { sys::igGetID_Ptr(p) };
Id(value)
}
/// Create [`Id`] from i32
pub fn new_id_int(&self, input: i32) -> Id {
let p = input as *const std::os::raw::c_void;
let value = unsafe { sys::igGetID_Ptr(p) };
Id(value)
}
/// Create [`Id`] from a pointer
pub fn new_id_ptr<T>(&self, input: &T) -> Id {
let p = input as *const T as *const sys::cty::c_void;
let value = unsafe { sys::igGetID_Ptr(p) };
Id(value)
}
/// Create [`Id`] from string
pub fn new_id_str(&self, s: impl AsRef<str>) -> Id {
let s = s.as_ref();
let s1 = s.as_ptr() as *const std::os::raw::c_char;
let value = unsafe {
let s2 = s1.add(s.len());
sys::igGetID_StrStr(s1, s2)
};
Id(value)
}
}
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`] 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");
/// });
/// ```
///
/// Same as [`Ui::window`] but using the "token based" `.begin()` approach.
///
/// ```no_run
/// # let mut ctx = imgui::Context::create();
/// # let ui = ctx.frame();
/// if let Some(wt) = ui
/// .window("Example Window")
/// .size([100.0, 50.0], imgui::Condition::FirstUseEver)
/// .begin()
/// {
/// ui.text("Window is visible");
/// // Window ends where where wt is dropped,
/// // or you could call
/// // if you want to let it drop on its own, name it `_wt`.
/// // never name it `_`, as this will drop it *immediately*.
/// wt.end();
/// };
/// ```
pub fn window<Label: AsRef<str>>(&self, name: Label) -> Window<'_, '_, Label> {
#[allow(deprecated)]
Window::new(self, name)
}
/// Begins constructing a child window with the given name.
///
/// Use child windows to begin into a self-contained independent scrolling/clipping
/// regions within a host window. Child windows can embed their own child.
pub fn child_window<Label: AsRef<str>>(&self, name: Label) -> ChildWindow<'_> {
#[allow(deprecated)]
ChildWindow::new(self, name)
}
/// Begins constructing a child window with the given name.
///
/// Use child windows to begin into a self-contained independent scrolling/clipping
/// regions within a host window. Child windows can embed their own child.
pub fn child_window_id(&self, id: Id) -> ChildWindow<'_> {
ChildWindow::new_id(self, id)
}
}
impl<'ui> Ui {
/// # Widgets: Input
/// Edits text in a single line input widget
#[doc(alias = "InputText", alias = "InputTextWithHint")]
pub fn input_text<'p, L: AsRef<str>>(
&'ui self,
label: L,
buf: &'p mut String,
) -> InputText<'ui, 'p, L> {
InputText::new(self, label, buf)
}
/// Edits text in a multi line widget. Similar to [`Self::input_text`]
/// but requires specifying a size. [`Self::content_region_avail`]
/// can be useful to make this take up all avaialble space
#[doc(alias = "InputText", alias = "InputTextMultiline")]
pub fn input_text_multiline<'p, L: AsRef<str>>(
&'ui self,
label: L,
buf: &'p mut String,
size: [f32; 2],
) -> InputTextMultiline<'ui, 'p, L> {
InputTextMultiline::new(self, label, buf, size)
}
/// Simple floating point number widget
#[doc(alias = "InputFloat")]
pub fn input_float<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut f32,
) -> InputScalar<'ui, 'p, f32, L> {
self.input_scalar(label, value)
}
/// Widget to edit two floats
#[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<str>,
T: Copy + Into<MintVec2>,
MintVec2: Into<T> + Into<[f32; 2]>,
{
InputFloat2::new(self, label, value)
}
/// Widget to edit 3 floats
#[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<str>,
T: Copy + Into<MintVec3>,
MintVec3: Into<T> + Into<[f32; 3]>,
{
InputFloat3::new(self, label, value)
}
/// Widget to edit 4 floats
#[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<str>,
T: Copy + Into<MintVec4>,
MintVec4: Into<T> + Into<[f32; 4]>,
{
InputFloat4::new(self, label, value)
}
/// Shortcut for [`Ui::input_scalar`]
#[doc(alias = "InputInt")]
pub fn input_int<'p, L: AsRef<str>>(
&'ui self,
label: L,
value: &'p mut i32,
) -> InputScalar<'ui, 'p, i32, L> {
self.input_scalar(label, value)
}
/// Shortcut for [`Ui::input_scalar`]
#[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<str>,
T: Copy + Into<MintIVec2>,
MintIVec2: Into<T> + Into<[i32; 2]>,
{
InputInt2::new(self, label, value)
}
/// Shortcut for [`Ui::input_scalar`]
#[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<str>,
T: Copy + Into<MintIVec3>,
MintIVec3: Into<T> + Into<[i32; 3]>,
{
InputInt3::new(self, label, value)
}
/// Shortcut for [`Ui::input_scalar`]
#[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<str>,
T: Copy + Into<MintIVec4>,
MintIVec4: Into<T> + Into<[i32; 4]>,
{
InputInt4::new(self, label, value)
}
/// Shows an input field for a scalar value. This is not limited to `f32` and `i32` and can be used with
/// any primitive scalar type e.g. `u8` and `f64`.
#[doc(alias = "InputScalar")]
pub fn input_scalar<'p, L, T>(
&'ui self,
label: L,
value: &'p mut T,
) -> InputScalar<'ui, 'p, T, L>
where
L: AsRef<str>,
T: internal::DataTypeKind,
{
InputScalar::new(self, label, value)
}
/// Shows a horizontal array of scalar value input fields. See [`input_scalar`].
///
/// [`input_scalar`]: Self::input_scalar
#[doc(alias = "InputScalarN")]
pub fn input_scalar_n<'p, L, T>(
&'ui self,
label: L,
values: &'p mut [T],
) -> InputScalarN<'ui, 'p, T, L>
where
L: AsRef<str>,
T: internal::DataTypeKind,
{
InputScalarN::new(self, label, values)
}
}
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], "I'm red!");
/// });
/// }
/// }
/// ```
#[doc(alias = "BeginTooltip", alias = "EndTootip")]
pub fn tooltip<F: FnOnce()>(&self, f: F) {
if unsafe { sys::igBeginTooltip() } {
f();
unsafe { sys::igEndTooltip() };
}
}
/// Construct a tooltip window that can have any kind of content.
///
/// Can return a `TooltipToken` that must be ended by calling `.end()`
#[doc(alias = "BeginTooltip")]
pub fn begin_tooltip(&self) -> Option<TooltipToken<'_>> {
if unsafe { sys::igBeginTooltip() } {
Some(TooltipToken::new(self))
} else {
None
}
}
/// Shortcut to call [`Self::tooltip`] with simple text content.
///
/// # 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 = "EndTooltip", alias = "SetTooltip")]
pub fn tooltip_text<T: AsRef<str>>(&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("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("Dangerous button");
/// });
/// }
/// ```
#[doc(alias = "BeginDisabled", alias = "EndDisabled")]
pub fn disabled<F: FnOnce()>(&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<F: FnOnce()>(&self, enabled: bool, f: F) {
self.disabled(!enabled, f)
}
}
// Widgets: ListBox
impl Ui {
#[doc(alias = "ListBox")]
pub fn list_box<'p, StringType: AsRef<str> + ?Sized>(
&self,
label: impl AsRef<str>,
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_start = handle.push(label);
// we do this in two allocations
let items_inner: Vec<usize> = items.iter().map(|&v| handle.push(v)).collect();
let items_inner: Vec<*const _> = items_inner
.into_iter()
.map(|v| handle.buffer.as_ptr().add(v) as *const _)
.collect();
let label_ptr = handle.buffer.as_ptr().add(label_start) as *const _;
(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<str> + ?Sized, const N: usize>(
// &self,
// label: impl AsRef<str>,
// 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 {
/// Plot a list of floats as a "sparkline" style plot
#[doc(alias = "PlotLines")]
pub fn plot_lines<'p, Label: AsRef<str>>(
&'ui self,
label: Label,
values: &'p [f32],
) -> PlotLines<'ui, 'p, Label> {
PlotLines::new(self, label, values)
}
/// Plot a list of floats as a histogram
#[doc(alias = "PlotHistogram")]
pub fn plot_histogram<'p, Label: AsRef<str>>(
&'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<T: AsRef<str>>(&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<T: AsRef<str>>(
&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.
///
/// The window draw list draws within the current
/// window. Coordinates are within the current window coordinates,
/// so `[0.0, 0.0]` would be at beginning of window
///
/// # 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)
}
/// Get draw list to draw behind all windows
///
/// Coordinates are in window coordinates, so `[0.0, 0.0]` is at
/// top left of the Dear ImGui window
///
/// See [`Self::get_window_draw_list`] for more details
#[must_use]
#[doc(alias = "GetBackgroundDrawList")]
pub fn get_background_draw_list(&self) -> DrawListMut<'_> {
DrawListMut::background(self)
}
/// Get draw list instance to draw above all window content
///
/// Coordinates are in window coordinates, so `[0.0, 0.0]` is at
/// top left of the Dear ImGui window
///
/// See [`Self::get_window_draw_list`] for more details
#[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,
}