From ff10eb01c877b08515bc4f2b23b4cbe45a7968f2 Mon Sep 17 00:00:00 2001 From: Jack Mac Date: Wed, 15 Sep 2021 12:14:05 -0400 Subject: [PATCH] added scare warning to string editing to explain null-termination --- imgui/src/draw_list.rs | 15 ++++- imgui/src/input_widget.rs | 113 +++++++++++++++++++++++++++++--------- imgui/src/stacks.rs | 6 +- 3 files changed, 105 insertions(+), 29 deletions(-) diff --git a/imgui/src/draw_list.rs b/imgui/src/draw_list.rs index 4ecf07c..e6882e5 100644 --- a/imgui/src/draw_list.rs +++ b/imgui/src/draw_list.rs @@ -373,7 +373,12 @@ impl<'ui> DrawListMut<'ui> { /// .build(); /// } /// ``` - pub fn add_image(&'ui self, texture_id: TextureId, p_min: [f32; 2], p_max: [f32; 2]) -> Image<'_> { + pub fn add_image( + &'ui self, + texture_id: TextureId, + p_min: [f32; 2], + p_max: [f32; 2], + ) -> Image<'_> { Image::new(self, texture_id, p_min, p_max) } @@ -562,7 +567,13 @@ pub struct Triangle<'ui> { } impl<'ui> Triangle<'ui> { - fn new(draw_list: &'ui DrawListMut<'_>, p1: [f32; 2], p2: [f32; 2], p3: [f32; 2], c: C) -> Self + fn new( + draw_list: &'ui DrawListMut<'_>, + p1: [f32; 2], + p2: [f32; 2], + p3: [f32; 2], + c: C, + ) -> Self where C: Into, { diff --git a/imgui/src/input_widget.rs b/imgui/src/input_widget.rs index 2658133..0a288bb 100644 --- a/imgui/src/input_widget.rs +++ b/imgui/src/input_widget.rs @@ -169,6 +169,20 @@ pub struct InputText<'ui, 'p, L, H = &'static str, T = PassthroughCallback> { } impl<'ui, 'p, L: AsRef> InputText<'ui, 'p, L> { + /// Creates a new input text widget to edit the given string. + /// + /// # String Editing + /// + /// Please note, ImGui requires this string to be null-terminated. We accomplish this + /// by appending and then removing a null terminator (`\0`) from the String you pass in. + /// This has several consequences: + /// 1. The string's backing buffer may be resized and relocated even without edits as result + /// of this pushed char. + /// 2. **The string will appear truncated if the string contains `\0` inside it.** This will not + /// cause memory *unsafety*, but it will limit your usage. If that's the case, please pre-process + /// your string. + /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. + /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String) -> Self { InputText { label, @@ -203,22 +217,22 @@ where impl_text_flags!(InputText); - /// By default (as of 0.8.0), imgui-rs will automatically handle string resizes - /// for [InputText] and [InputTextMultiline]. - /// - /// If, for some reason, you don't want this, you can run this function to prevent this. - /// In that case, edits which would cause a resize will not occur. - /// - /// # Safety - /// Importantly, we silently push and pop a `\0` to the string given here. - /// If you do not want mutable access (ie, do not want that string to resize), - /// you **must** make sure to null-terminate it yourself. This is janky, but ImGui - /// expects a null termination, and we didn't want to re-allocate an entire string per call. - #[inline] - pub unsafe fn do_not_resize(mut self) -> Self { - self.flags.remove(InputTextFlags::CALLBACK_RESIZE); - self - } + // I am commenting this ability out for now -- because we need to push `\0` for imgui, + // we may resize the buffer no matter what, and we must do that. + // The solution for this will be, I suspect, to build a second api channel that takes + // an `&mut CStr`, which is ugly! I suspect few to none will want no-resizing, so I'm deferring + // fixing the problem. -- sanbox-irl 09/15/2021, see #523 for more + // + // /// By default (as of 0.8.0), imgui-rs will automatically handle string resizes + // /// for [InputText] and [InputTextMultiline]. + // /// + // /// If, for some reason, you don't want this, you can run this function to prevent this. + // /// In that case, edits which would cause a resize will not occur. + // /// #[inline] + // pub unsafe fn do_not_resize(mut self) -> Self { + // self.flags.remove(InputTextFlags::CALLBACK_RESIZE); + // self + // } #[inline] pub fn callback( @@ -251,6 +265,20 @@ where } } + /// Builds the string editor, performing string editing operations. + /// + /// # String Editing + /// + /// Please note, ImGui requires this string to be null-terminated. We accomplish this + /// by appending and then removing a null terminator (`\0`) from the String you pass in. + /// This has several consequences: + /// 1. The string's backing buffer may be resized and relocated even without edits as result + /// of this pushed char. + /// 2. **The string will appear truncated if the string contains `\0` inside it.** This will not + /// cause memory *unsafety*, but it will limit your usage. If that's the case, please pre-process + /// your string. + /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. + /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. pub fn build(self) -> bool { // needs to be null-terminated! self.buf.push('\0'); @@ -309,6 +337,20 @@ pub struct InputTextMultiline<'ui, 'p, L, T = PassthroughCallback> { } impl<'ui, 'p, L: AsRef> InputTextMultiline<'ui, 'p, L, PassthroughCallback> { + /// Creates a new input text widget to edit the given string. + /// + /// # String Editing + /// + /// Please note, ImGui requires this string to be null-terminated. We accomplish this + /// by appending and then removing a null terminator (`\0`) from the String you pass in. + /// This has several consequences: + /// 1. The string's backing buffer may be resized and relocated even without edits as result + /// of this pushed char. + /// 2. **The string will appear truncated if the string contains `\0` inside it.** This will not + /// cause memory *unsafety*, but it will limit your usage. If that's the case, please pre-process + /// your string. + /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. + /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String, size: [f32; 2]) -> Self { InputTextMultiline { label, @@ -324,16 +366,21 @@ impl<'ui, 'p, L: AsRef> InputTextMultiline<'ui, 'p, L, PassthroughCallback> impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef> InputTextMultiline<'ui, 'p, L, T> { impl_text_flags!(InputText); - /// By default (as of 0.8.0), imgui-rs will automatically handle string resizes - /// for [InputText] and [InputTextMultiline]. - /// - /// If, for some reason, you don't want this, you can run this function to prevent this. - /// In that case, edits which would cause a resize will not occur. - #[inline] - pub fn do_not_resize(mut self) -> Self { - self.flags.remove(InputTextFlags::CALLBACK_RESIZE); - self - } + // I am commenting this ability out for now -- because we need to push `\0` for imgui, + // we may resize the buffer no matter what, and we must do that. + // The solution for this will be, I suspect, to build a second api channel that takes + // an `&mut CStr`, which is ugly! I suspect few to none will want no-resizing, so I'm deferring + // fixing the problem. -- sanbox-irl 09/15/2021, see #523 for more + // /// By default (as of 0.8.0), imgui-rs will automatically handle string resizes + // /// for [InputText] and [InputTextMultiline]. + // /// + // /// If, for some reason, you don't want this, you can run this function to prevent this. + // /// In that case, edits which would cause a resize will not occur. + // #[inline] + // pub fn do_not_resize(mut self) -> Self { + // self.flags.remove(InputTextFlags::CALLBACK_RESIZE); + // self + // } #[inline] pub fn callback( @@ -364,6 +411,20 @@ impl<'ui, 'p, T: InputTextCallbackHandler, L: AsRef> InputTextMultiline<'ui } } + /// Builds the string editor, performing string editing operations. + /// + /// # String Editing + /// + /// Please note, ImGui requires this string to be null-terminated. We accomplish this + /// by appending and then removing a null terminator (`\0`) from the String you pass in. + /// This has several consequences: + /// 1. The string's backing buffer may be resized and relocated even without edits as result + /// of this pushed char. + /// 2. **The string will appear truncated if the string contains `\0` inside it.** This will not + /// cause memory *unsafety*, but it will limit your usage. If that's the case, please pre-process + /// your string. + /// 3. Truncations by ImGui appear to be done primarily by insertions of `\0` to the truncation point. + /// We will handle this for you and edit the string "properly" too, but this might show up in callbacks. pub fn build(self) -> bool { // needs to be null-terminated! self.buf.push('\0'); diff --git a/imgui/src/stacks.rs b/imgui/src/stacks.rs index 37fdced..b507741 100644 --- a/imgui/src/stacks.rs +++ b/imgui/src/stacks.rs @@ -59,7 +59,11 @@ impl<'ui> Ui<'ui> { /// color.pop(); /// ``` #[doc(alias = "PushStyleColorVec4")] - pub fn push_style_color(&self, style_color: StyleColor, color: [f32; 4]) -> ColorStackToken<'_> { + pub fn push_style_color( + &self, + style_color: StyleColor, + color: [f32; 4], + ) -> ColorStackToken<'_> { unsafe { sys::igPushStyleColor_Vec4(style_color as i32, color.into()) }; ColorStackToken::new(self) }