transmogrified the Id struct

This commit is contained in:
Jack Mac 2021-10-01 16:21:20 -04:00
parent 203780c884
commit 074c40e927
6 changed files with 177 additions and 86 deletions

View File

@ -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: `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 ## [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! 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!

View File

@ -33,7 +33,7 @@ fn main() {
let _label_id = ui.push_id(it); let _label_id = ui.push_id(it);
ui.text(it); ui.text(it);
for num in 0..5 { for num in 0..5 {
let _num_id = ui.push_id(num); let _num_id = ui.push_id_usize(num);
ui.same_line(); ui.same_line();
if ui.button("Example") { if ui.button("Example") {
println!("{}: {}", it, num); println!("{}: {}", it, num);

View File

@ -5,7 +5,7 @@
pub extern crate imgui_sys as sys; pub extern crate imgui_sys as sys;
use std::cell; use std::cell;
use std::os::raw::{c_char, c_void}; use std::os::raw::c_char;
pub use self::clipboard::*; pub use self::clipboard::*;
pub use self::color::ImColor32; pub use self::color::ImColor32;
@ -269,69 +269,124 @@ impl Ui {
} }
} }
/// Unique ID used by widgets /// Unique ID used by widgets.
#[derive(Copy, Clone, Debug, Eq, PartialEq)] ///
pub enum Id<'a> { /// This represents a hash of the current stack of Ids used in ImGui + the
Int(i32), /// input provided. It is only used in a few places directly in the
Str(&'a str), /// codebase, but you can think of it as effectively allowing you to
Ptr(*const c_void), /// 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<i32> for Id<'static> { impl Id {
#[inline] #[allow(non_snake_case)]
fn from(i: i32) -> Self { pub fn Int(input: i32, ui: &Ui) -> Self {
Id::Int(i) ui.new_id_int(input)
}
#[allow(non_snake_case)]
pub fn Str(input: impl AsRef<str>, ui: &Ui) -> Self {
ui.new_id_str(input)
}
#[allow(non_snake_case)]
pub fn Ptr<T>(input: &T, ui: &Ui) -> Self {
ui.new_id_ptr(input)
} }
} }
impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> { impl Ui {
#[inline] pub fn new_id(&self, input: usize) -> Id {
fn from(s: &'a T) -> Self { let p = input as *const std::os::raw::c_void;
Id::Str(s.as_ref()) 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<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)
}
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<T> From<*const T> for Id<'static> { // /// Unique ID used by widgets
#[inline] // pub enum Id<'a> {
fn from(p: *const T) -> Self { // Int(i32),
Id::Ptr(p as *const c_void) // Str(&'a str),
} // Ptr(*const c_void),
} // }
impl<T> From<*mut T> for Id<'static> { // impl From<i32> for Id<'static> {
#[inline] // #[inline]
fn from(p: *mut T) -> Self { // fn from(i: i32) -> Self {
Id::Ptr(p as *const T as *const c_void) // Id::Int(i)
} // }
} // }
impl<'a> Id<'a> { // impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> {
// this is used in the tables-api and possibly elsewhere, // #[inline]
// but not with just default features... // fn from(s: &'a T) -> Self {
#[allow(dead_code)] // Id::Str(s.as_ref())
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> { // impl<T> From<*const T> for Id<'static> {
fn default() -> Self { // #[inline]
Self::Int(0) // fn from(p: *const T) -> Self {
} // Id::Ptr(p as *const c_void)
} // }
// }
// impl<T> 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 { impl Ui {
/// # Windows /// # Windows
@ -390,7 +445,7 @@ impl Ui {
/// ///
/// Use child windows to begin into a self-contained independent scrolling/clipping /// Use child windows to begin into a self-contained independent scrolling/clipping
/// regions within a host window. Child windows can embed their own child. /// 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) ChildWindow::new_id(self, id)
} }
} }

View File

@ -3,9 +3,9 @@ use crate::internal::RawCast;
use crate::math::MintVec4; use crate::math::MintVec4;
use crate::style::{StyleColor, StyleVar}; use crate::style::{StyleColor, StyleVar};
use crate::sys; use crate::sys;
use crate::{Id, Ui}; use crate::Ui;
use std::mem; use std::mem;
use std::os::raw::{c_char, c_void}; use std::os::raw::c_char;
/// # Parameter stacks (shared) /// # Parameter stacks (shared)
impl Ui { impl Ui {
@ -386,7 +386,6 @@ impl IdStackToken<'_> {
/// # ID stack /// # ID stack
impl<'ui> Ui { impl<'ui> Ui {
/// Pushes an identifier to the ID stack. /// 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()` /// Returns an `IdStackToken` that can be popped by calling `.end()`
/// or by dropping manually. /// or by dropping manually.
@ -462,20 +461,55 @@ impl<'ui> Ui {
/// }); /// });
/// ``` /// ```
#[doc(alias = "PushId")] #[doc(alias = "PushId")]
pub fn push_id<'a, I: Into<Id<'a>>>(&'ui self, id: I) -> IdStackToken<'ui> { pub fn push_id(&self, s: impl AsRef<str>) -> IdStackToken<'_> {
let id = id.into();
unsafe { unsafe {
match id { let s = s.as_ref();
Id::Int(i) => sys::igPushID_Int(i), let start = s.as_ptr() as *const c_char;
Id::Str(s) => { let end = start.add(s.len());
let start = s.as_ptr() as *const c_char; sys::igPushID_StrStr(start, end)
let end = start.add(s.len());
sys::igPushID_StrStr(start, end)
}
Id::Ptr(p) => sys::igPushID_Ptr(p as *const c_void),
}
} }
IdStackToken::new(self) 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<T>(&self, value: &T) -> IdStackToken<'_> {
unsafe { sys::igPushID_Ptr(value as *const T as *const _) }
IdStackToken::new(self)
}
} }

View File

@ -320,10 +320,10 @@ impl Ui {
/// Takes an array of table header information, the length of which determines /// Takes an array of table header information, the length of which determines
/// how many columns will be created. /// how many columns will be created.
#[must_use = "if return is dropped immediately, table is ended immediately."] #[must_use = "if return is dropped immediately, table is ended immediately."]
pub fn begin_table_header<'a, Name: AsRef<str>, const N: usize>( pub fn begin_table_header<Name: AsRef<str>, const N: usize>(
&self, &self,
str_id: impl AsRef<str>, str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N], column_data: [TableColumnSetup<Name>; N],
) -> Option<TableToken<'_>> { ) -> Option<TableToken<'_>> {
self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty()) 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 /// Takes an array of table header information, the length of which determines
/// how many columns will be created. /// how many columns will be created.
#[must_use = "if return is dropped immediately, table is ended immediately."] #[must_use = "if return is dropped immediately, table is ended immediately."]
pub fn begin_table_header_with_flags<'a, Name: AsRef<str>, const N: usize>( pub fn begin_table_header_with_flags<Name: AsRef<str>, const N: usize>(
&self, &self,
str_id: impl AsRef<str>, str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N], column_data: [TableColumnSetup<Name>; N],
flags: TableFlags, flags: TableFlags,
) -> Option<TableToken<'_>> { ) -> Option<TableToken<'_>> {
self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0) 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 /// Takes an array of table header information, the length of which determines
/// how many columns will be created. /// how many columns will be created.
#[must_use = "if return is dropped immediately, table is ended immediately."] #[must_use = "if return is dropped immediately, table is ended immediately."]
pub fn begin_table_header_with_sizing<'a, Name: AsRef<str>, const N: usize>( pub fn begin_table_header_with_sizing<Name: AsRef<str>, const N: usize>(
&self, &self,
str_id: impl AsRef<str>, str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N], column_data: [TableColumnSetup<Name>; N],
flags: TableFlags, flags: TableFlags,
outer_size: [f32; 2], outer_size: [f32; 2],
inner_width: f32, inner_width: f32,
@ -533,13 +533,13 @@ impl Ui {
/// row and automatically submit a table header for each column. /// row and automatically submit a table header for each column.
/// Headers are required to perform: reordering, sorting, and opening the context menu (though, /// 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]. /// the context menu can also be made available in columns body using [TableFlags::CONTEXT_MENU_IN_BODY].
pub fn table_setup_column_with<N: AsRef<str>>(&self, data: TableColumnSetup<'_, N>) { pub fn table_setup_column_with<N: AsRef<str>>(&self, data: TableColumnSetup<N>) {
unsafe { unsafe {
sys::igTableSetupColumn( sys::igTableSetupColumn(
self.scratch_txt(data.name), self.scratch_txt(data.name),
data.flags.bits() as i32, data.flags.bits() as i32,
data.init_width_or_weight, 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 /// 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). /// via [begin_table_header](Ui::begin_table_header) or [table_setup_column](Ui::table_setup_column).
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct TableColumnSetup<'a, Name> { pub struct TableColumnSetup<Name> {
/// The name of column to be displayed to users. /// The name of column to be displayed to users.
pub name: Name, pub name: Name,
/// The flags this column will have. /// The flags this column will have.
@ -741,16 +741,16 @@ pub struct TableColumnSetup<'a, Name> {
/// The width or weight of the given column. /// The width or weight of the given column.
pub init_width_or_weight: f32, pub init_width_or_weight: f32,
/// A user_id, primarily used in sorting operations. /// A user_id, primarily used in sorting operations.
pub user_id: Id<'a>, pub user_id: Id,
} }
impl<'a, Name: AsRef<str>> TableColumnSetup<'a, Name> { impl<'a, Name: AsRef<str>> TableColumnSetup<Name> {
pub fn new(name: Name) -> Self { pub fn new(name: Name) -> Self {
Self { Self {
name, name,
flags: TableColumnFlags::empty(), flags: TableColumnFlags::empty(),
init_width_or_weight: 0.0, init_width_or_weight: 0.0,
user_id: Id::Int(0), user_id: Id::default(),
} }
} }
} }

View File

@ -23,16 +23,16 @@ impl<'ui> ChildWindow<'ui> {
/// Creates a new child window builder with the str. /// Creates a new child window builder with the str.
#[doc(alias = "BeginChildID")] #[doc(alias = "BeginChildID")]
pub fn new(ui: &'ui Ui, name: impl AsRef<str>) -> Self { pub fn new(ui: &'ui Ui, name: impl AsRef<str>) -> Self {
let id = Id::Str(name.as_ref()); let id = ui.new_id_str(name);
Self::new_id(ui, id) Self::new_id(ui, id)
} }
/// Creates a new child window builder with the given imgui id. /// Creates a new child window builder with the given imgui id.
#[doc(alias = "BeginChildID")] #[doc(alias = "BeginChildID")]
pub fn new_id(ui: &'ui Ui, id: Id<'_>) -> Self { pub fn new_id(ui: &'ui Ui, id: Id) -> Self {
Self { Self {
ui, ui,
id: id.as_imgui_id(), id: id.0,
flags: WindowFlags::empty(), flags: WindowFlags::empty(),
size: [0.0, 0.0], size: [0.0, 0.0],
content_size: [0.0, 0.0], content_size: [0.0, 0.0],