diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 6523c74..93c8407 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -10,6 +10,8 @@ - BREAKING: `SharedFontAtlas` now hides an `Rc` within its wrapper -- this simplifies the codebase and more accurately reflects how we expect `SharedFontAtlas` to be used (ie, you're probably going to set it up once, and then give it around, rather than constantly edit it). `SharedFontAtlas` users, if this change is very bad for you, please let us know with issues! +- BREAKING: `Id` is now a simpler facade, but requires the `Ui` struct to generate. `push_id`, equally, has been split into multiple functions for simplicity. + ## [0.8.0] - 2021-09-17 Welcome to the `0.8.0` update. This is one of the largest updates imgui-rs has ever seen; it will generate errors in a `0.7` project, but hopefully it should be both quick to fix, and enjoyable to update. See our [release page](https://github.com/imgui-rs/imgui-rs/releases/tag/v0.8.0) for more information and a list of contributors to this cycle. Thank you to everyone who uses `imgui-rs`, files issues, and spend their time and effort to PR new changes into the codebase. Because of all that effort, this is by far the best `imgui-rs` has looked! diff --git a/imgui-examples/examples/id_wrangling.rs b/imgui-examples/examples/id_wrangling.rs index fbd0ded..ee8eb7d 100644 --- a/imgui-examples/examples/id_wrangling.rs +++ b/imgui-examples/examples/id_wrangling.rs @@ -33,7 +33,7 @@ fn main() { let _label_id = ui.push_id(it); ui.text(it); for num in 0..5 { - let _num_id = ui.push_id(num); + let _num_id = ui.push_id_usize(num); ui.same_line(); if ui.button("Example") { println!("{}: {}", it, num); diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 34a5ede..980bf99 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -5,7 +5,7 @@ pub extern crate imgui_sys as sys; use std::cell; -use std::os::raw::{c_char, c_void}; +use std::os::raw::c_char; pub use self::clipboard::*; pub use self::color::ImColor32; @@ -269,69 +269,124 @@ impl Ui { } } -/// Unique ID used by widgets -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum Id<'a> { - Int(i32), - Str(&'a str), - Ptr(*const c_void), -} +/// 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. +/// +/// Previously, this was erroneously constructed with `From` implementations. +/// Now, however, it is made from the `Ui` object directly, with a few +/// deprecated helper methods here. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] +pub struct Id(pub(crate) u32); -impl From for Id<'static> { - #[inline] - fn from(i: i32) -> Self { - Id::Int(i) +impl Id { + #[allow(non_snake_case)] + pub fn Int(input: i32, ui: &Ui) -> Self { + ui.new_id_int(input) + } + + #[allow(non_snake_case)] + pub fn Str(input: impl AsRef, ui: &Ui) -> Self { + ui.new_id_str(input) + } + + #[allow(non_snake_case)] + pub fn Ptr(input: &T, ui: &Ui) -> Self { + ui.new_id_ptr(input) } } -impl<'a, T: ?Sized + AsRef> From<&'a T> for Id<'a> { - #[inline] - fn from(s: &'a T) -> Self { - Id::Str(s.as_ref()) +impl Ui { + 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) + } + + 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) + } + + pub fn new_id_ptr(&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) + } + + pub fn new_id_str(&self, s: impl AsRef) -> 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 From<*const T> for Id<'static> { - #[inline] - fn from(p: *const T) -> Self { - Id::Ptr(p as *const c_void) - } -} +// /// Unique ID used by widgets +// pub enum Id<'a> { +// Int(i32), +// Str(&'a str), +// Ptr(*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 From for Id<'static> { +// #[inline] +// fn from(i: i32) -> Self { +// Id::Int(i) +// } +// } -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, T: ?Sized + AsRef> From<&'a T> for Id<'a> { +// #[inline] +// fn from(s: &'a T) -> Self { +// Id::Str(s.as_ref()) +// } +// } -impl<'a> Default for Id<'a> { - fn default() -> Self { - Self::Int(0) - } -} +// 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 Ui { /// # Windows @@ -390,7 +445,7 @@ impl Ui { /// /// 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<'_> { + pub fn child_window_id(&self, id: Id) -> ChildWindow<'_> { ChildWindow::new_id(self, id) } } diff --git a/imgui/src/stacks.rs b/imgui/src/stacks.rs index 0cc4b52..69c9eb7 100644 --- a/imgui/src/stacks.rs +++ b/imgui/src/stacks.rs @@ -3,9 +3,9 @@ use crate::internal::RawCast; use crate::math::MintVec4; use crate::style::{StyleColor, StyleVar}; use crate::sys; -use crate::{Id, Ui}; +use crate::Ui; use std::mem; -use std::os::raw::{c_char, c_void}; +use std::os::raw::c_char; /// # Parameter stacks (shared) impl Ui { @@ -386,7 +386,6 @@ impl IdStackToken<'_> { /// # ID stack impl<'ui> Ui { /// Pushes an identifier to the ID stack. - /// This can be called with an integer, a string, or a pointer. /// /// Returns an `IdStackToken` that can be popped by calling `.end()` /// or by dropping manually. @@ -462,20 +461,55 @@ impl<'ui> Ui { /// }); /// ``` #[doc(alias = "PushId")] - pub fn push_id<'a, I: Into>>(&'ui self, id: I) -> IdStackToken<'ui> { - let id = id.into(); - + pub fn push_id(&self, s: impl AsRef) -> IdStackToken<'_> { unsafe { - match id { - Id::Int(i) => sys::igPushID_Int(i), - Id::Str(s) => { - let start = s.as_ptr() as *const c_char; - let end = start.add(s.len()); - sys::igPushID_StrStr(start, end) - } - Id::Ptr(p) => sys::igPushID_Ptr(p as *const c_void), - } + let s = s.as_ref(); + let start = s.as_ptr() as *const c_char; + let end = start.add(s.len()); + sys::igPushID_StrStr(start, end) } IdStackToken::new(self) } + + /// Pushes a `usize` to the ID stack. + /// + /// Returns an `IdStackToken` that can be popped by calling `.end()` + /// or by dropping manually. + /// + /// See [push_id] for more information. + /// + /// [push_id]: Self::push_id + #[doc(alias = "PushId")] + pub fn push_id_usize(&self, id: usize) -> IdStackToken<'_> { + unsafe { sys::igPushID_Ptr(id as *const _) } + IdStackToken::new(self) + } + + /// Pushes an `i32` to the ID stack. + /// + /// Returns an `IdStackToken` that can be popped by calling `.end()` + /// or by dropping manually. + /// + /// See [push_id] for more information. + /// + /// [push_id]: Self::push_id + #[doc(alias = "PushId")] + pub fn push_id_int(&self, id: i32) -> IdStackToken<'_> { + unsafe { sys::igPushID_Int(id) } + IdStackToken::new(self) + } + + /// Pushes a `ptr` to the ID stack. + /// + /// Returns an `IdStackToken` that can be popped by calling `.end()` + /// or by dropping manually. + /// + /// See [push_id] for more information. + /// + /// [push_id]: Self::push_id + #[doc(alias = "PushId")] + pub fn push_id_ptr(&self, value: &T) -> IdStackToken<'_> { + unsafe { sys::igPushID_Ptr(value as *const T as *const _) } + IdStackToken::new(self) + } } diff --git a/imgui/src/tables.rs b/imgui/src/tables.rs index a5a9503..0d52094 100644 --- a/imgui/src/tables.rs +++ b/imgui/src/tables.rs @@ -320,10 +320,10 @@ impl Ui { /// Takes an array of table header information, the length of which determines /// how many columns will be created. #[must_use = "if return is dropped immediately, table is ended immediately."] - pub fn begin_table_header<'a, Name: AsRef, const N: usize>( + pub fn begin_table_header, const N: usize>( &self, str_id: impl AsRef, - column_data: [TableColumnSetup<'a, Name>; N], + column_data: [TableColumnSetup; N], ) -> Option> { self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty()) } @@ -333,10 +333,10 @@ impl Ui { /// Takes an array of table header information, the length of which determines /// how many columns will be created. #[must_use = "if return is dropped immediately, table is ended immediately."] - pub fn begin_table_header_with_flags<'a, Name: AsRef, const N: usize>( + pub fn begin_table_header_with_flags, const N: usize>( &self, str_id: impl AsRef, - column_data: [TableColumnSetup<'a, Name>; N], + column_data: [TableColumnSetup; N], flags: TableFlags, ) -> Option> { self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0) @@ -347,10 +347,10 @@ impl Ui { /// Takes an array of table header information, the length of which determines /// how many columns will be created. #[must_use = "if return is dropped immediately, table is ended immediately."] - pub fn begin_table_header_with_sizing<'a, Name: AsRef, const N: usize>( + pub fn begin_table_header_with_sizing, const N: usize>( &self, str_id: impl AsRef, - column_data: [TableColumnSetup<'a, Name>; N], + column_data: [TableColumnSetup; N], flags: TableFlags, outer_size: [f32; 2], inner_width: f32, @@ -533,13 +533,13 @@ impl Ui { /// row and automatically submit a table header for each column. /// Headers are required to perform: reordering, sorting, and opening the context menu (though, /// the context menu can also be made available in columns body using [TableFlags::CONTEXT_MENU_IN_BODY]. - pub fn table_setup_column_with>(&self, data: TableColumnSetup<'_, N>) { + pub fn table_setup_column_with>(&self, data: TableColumnSetup) { unsafe { sys::igTableSetupColumn( self.scratch_txt(data.name), data.flags.bits() as i32, data.init_width_or_weight, - data.user_id.as_imgui_id(), + data.user_id.0, ) } } @@ -733,7 +733,7 @@ impl Ui { /// A struct containing all the data needed to setup a table column header /// via [begin_table_header](Ui::begin_table_header) or [table_setup_column](Ui::table_setup_column). #[derive(Debug, Default)] -pub struct TableColumnSetup<'a, Name> { +pub struct TableColumnSetup { /// The name of column to be displayed to users. pub name: Name, /// The flags this column will have. @@ -741,16 +741,16 @@ pub struct TableColumnSetup<'a, Name> { /// The width or weight of the given column. pub init_width_or_weight: f32, /// A user_id, primarily used in sorting operations. - pub user_id: Id<'a>, + pub user_id: Id, } -impl<'a, Name: AsRef> TableColumnSetup<'a, Name> { +impl<'a, Name: AsRef> TableColumnSetup { pub fn new(name: Name) -> Self { Self { name, flags: TableColumnFlags::empty(), init_width_or_weight: 0.0, - user_id: Id::Int(0), + user_id: Id::default(), } } } diff --git a/imgui/src/window/child_window.rs b/imgui/src/window/child_window.rs index 2f5b378..39d444d 100644 --- a/imgui/src/window/child_window.rs +++ b/imgui/src/window/child_window.rs @@ -23,16 +23,16 @@ impl<'ui> ChildWindow<'ui> { /// Creates a new child window builder with the str. #[doc(alias = "BeginChildID")] pub fn new(ui: &'ui Ui, name: impl AsRef) -> Self { - let id = Id::Str(name.as_ref()); + let id = ui.new_id_str(name); Self::new_id(ui, id) } /// Creates a new child window builder with the given imgui id. #[doc(alias = "BeginChildID")] - pub fn new_id(ui: &'ui Ui, id: Id<'_>) -> Self { + pub fn new_id(ui: &'ui Ui, id: Id) -> Self { Self { ui, - id: id.as_imgui_id(), + id: id.0, flags: WindowFlags::empty(), size: [0.0, 0.0], content_size: [0.0, 0.0],