Skip to content

Commit

Permalink
transmogrified the Id struct
Browse files Browse the repository at this point in the history
  • Loading branch information
sanbox-irl committed Oct 1, 2021
1 parent 203780c commit 074c40e
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 82 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
2 changes: 1 addition & 1 deletion imgui-examples/examples/id_wrangling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
157 changes: 106 additions & 51 deletions imgui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -269,70 +269,125 @@ 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<i32> 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)
}
}

impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> {
#[inline]
fn from(s: &'a T) -> Self {
Id::Str(s.as_ref())
#[allow(non_snake_case)]
pub fn Str(input: impl AsRef<str>, ui: &Ui) -> Self {
ui.new_id_str(input)
}
}

impl<T> From<*const T> for Id<'static> {
#[inline]
fn from(p: *const T) -> Self {
Id::Ptr(p as *const c_void)
#[allow(non_snake_case)]
pub fn Ptr<T>(input: &T, ui: &Ui) -> Self {
ui.new_id_ptr(input)
}
}

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 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)
}
}

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,
}
}
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)
}
}

impl<'a> Default for Id<'a> {
fn default() -> Self {
Self::Int(0)
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)
}
}

// /// Unique ID used by widgets
// pub enum Id<'a> {
// Int(i32),
// Str(&'a str),
// Ptr(*const c_void),
// }

// impl From<i32> for Id<'static> {
// #[inline]
// fn from(i: i32) -> Self {
// Id::Int(i)
// }
// }

// impl<'a, T: ?Sized + AsRef<str>> From<&'a T> for Id<'a> {
// #[inline]
// fn from(s: &'a T) -> Self {
// Id::Str(s.as_ref())
// }
// }

// impl<T> From<*const T> for Id<'static> {
// #[inline]
// 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 {
/// # Windows
/// Start constructing a window.
Expand Down Expand Up @@ -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)
}
}
Expand Down
64 changes: 49 additions & 15 deletions imgui/src/stacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -462,20 +461,55 @@ impl<'ui> Ui {
/// });
/// ```
#[doc(alias = "PushId")]
pub fn push_id<'a, I: Into<Id<'a>>>(&'ui self, id: I) -> IdStackToken<'ui> {
let id = id.into();

pub fn push_id(&self, s: impl AsRef<str>) -> 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<T>(&self, value: &T) -> IdStackToken<'_> {
unsafe { sys::igPushID_Ptr(value as *const T as *const _) }
IdStackToken::new(self)
}
}
24 changes: 12 additions & 12 deletions imgui/src/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<str>, const N: usize>(
pub fn begin_table_header<Name: AsRef<str>, const N: usize>(
&self,
str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N],
column_data: [TableColumnSetup<Name>; N],
) -> Option<TableToken<'_>> {
self.begin_table_header_with_flags(str_id, column_data, TableFlags::empty())
}
Expand All @@ -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<str>, const N: usize>(
pub fn begin_table_header_with_flags<Name: AsRef<str>, const N: usize>(
&self,
str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N],
column_data: [TableColumnSetup<Name>; N],
flags: TableFlags,
) -> Option<TableToken<'_>> {
self.begin_table_header_with_sizing(str_id, column_data, flags, [0.0, 0.0], 0.0)
Expand All @@ -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<str>, const N: usize>(
pub fn begin_table_header_with_sizing<Name: AsRef<str>, const N: usize>(
&self,
str_id: impl AsRef<str>,
column_data: [TableColumnSetup<'a, Name>; N],
column_data: [TableColumnSetup<Name>; N],
flags: TableFlags,
outer_size: [f32; 2],
inner_width: f32,
Expand Down Expand Up @@ -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<N: AsRef<str>>(&self, data: TableColumnSetup<'_, N>) {
pub fn table_setup_column_with<N: AsRef<str>>(&self, data: TableColumnSetup<N>) {
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,
)
}
}
Expand Down Expand Up @@ -733,24 +733,24 @@ 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<Name> {
/// The name of column to be displayed to users.
pub name: Name,
/// The flags this column will have.
pub flags: TableColumnFlags,
/// 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<str>> TableColumnSetup<'a, Name> {
impl<'a, Name: AsRef<str>> TableColumnSetup<Name> {
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(),
}
}
}
Expand Down
Loading

0 comments on commit 074c40e

Please sign in to comment.