diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index f62eaa054..7eb86bd16 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -33,6 +33,8 @@ struct State { text_with_hint: String, text_multiline: String, i0: i32, + u0: u64, + d0: f64, f0: f32, vec2f: [f32; 2], vec3f: [f32; 3], @@ -95,7 +97,9 @@ impl Default for State { text_with_hint, text_multiline, i0: 123, + u0: 1234, f0: 0.001, + d0: 0.0001, vec2f: [0.10, 0.20], vec3f: [0.10, 0.20, 0.30], vec2i: [10, 20], @@ -538,15 +542,20 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.input_int("input int", &mut state.i0).build(); // Drag::new("drag int").build(ui, &mut state.i0); ui.input_float("input float", &mut state.f0) - .step(0.01) - .step_fast(1.0) - .build(); + .step(0.01) + .step_fast(1.0) + .build(); Drag::new("drag float").range(-1.0, 1.0).speed(0.001).build(ui, &mut state.f0); ui.input_float3("input float3", &mut state.vec3f) - .build(); + .build(); ColorEdit3::new("color 1", &mut state.col1).build(ui); ColorEdit4::new("color 2", &mut state.col2).build(ui); + ui.input_scalar("input scalar i64", &mut state.u0).build(ui); + ui.input_scalar("input scalar f64", &mut state.d0).build(ui); + ui.input_scalar_n("input scalar int array", &mut state.vec3i).build(ui); + ui.input_scalar_n("input scalar float array", &mut state.vec3f).build(ui); + TreeNode::new("Multi-component Widgets").build(ui, || { ui.input_float2("input float2", &mut state.vec2f) .build(); diff --git a/imgui/src/input_widget.rs b/imgui/src/input_widget.rs index 6e3f073c7..a2e329df2 100644 --- a/imgui/src/input_widget.rs +++ b/imgui/src/input_widget.rs @@ -1,7 +1,9 @@ use bitflags::bitflags; use std::ops::Range; use std::os::raw::{c_char, c_int, c_void}; +use std::ptr; +use crate::internal::DataTypeKind; use crate::math::*; use crate::sys; use crate::Ui; @@ -514,11 +516,12 @@ impl<'ui, 'p, L: AsRef> InputInt<'ui, 'p, L> { } #[must_use] -pub struct InputFloat<'ui, 'p, L> { +pub struct InputFloat<'ui, 'p, L, F = &'static str> { label: L, value: &'p mut f32, step: f32, step_fast: f32, + display_format: Option, flags: InputTextFlags, ui: &'ui Ui, } @@ -530,19 +533,36 @@ impl<'ui, 'p, L: AsRef> InputFloat<'ui, 'p, L> { value, step: 0.0, step_fast: 0.0, + display_format: None, flags: InputTextFlags::empty(), ui, } } + pub fn display_format>(self, display_format: F2) -> InputFloat<'ui, 'p, L, F2> { + InputFloat { + value: self.value, + label: self.label, + step: self.step, + step_fast: self.step_fast, + display_format: Some(display_format), + flags: self.flags, + ui: self.ui, + } + } + pub fn build(self) -> bool { + let (one, two) = self + .ui + .scratch_txt_with_opt(self.label, self.display_format); + unsafe { sys::igInputFloat( - self.ui.scratch_txt(self.label), + one, self.value as *mut f32, self.step, self.step_fast, - b"%.3f\0".as_ptr() as *const _, + two, self.flags.bits() as i32, ) } @@ -555,9 +575,10 @@ impl<'ui, 'p, L: AsRef> InputFloat<'ui, 'p, L> { macro_rules! impl_input_floatn { ($InputFloatN:ident, $MINT_TARGET:ty, $N:expr, $igInputFloatN:ident) => { #[must_use] - pub struct $InputFloatN<'ui, 'p, L, T> { + pub struct $InputFloatN<'ui, 'p, L, T, F = &'static str> { label: L, value: &'p mut T, + display_format: Option, flags: InputTextFlags, ui: &'ui Ui, } @@ -572,22 +593,35 @@ macro_rules! impl_input_floatn { $InputFloatN { label, value, + display_format: None, flags: InputTextFlags::empty(), ui, } } + pub fn display_format>( + self, + display_format: F2, + ) -> $InputFloatN<'ui, 'p, L, T, F2> { + $InputFloatN { + label: self.label, + value: self.value, + display_format: Some(display_format), + flags: self.flags, + ui: self.ui, + } + } + pub fn build(self) -> bool { let value: $MINT_TARGET = (*self.value).into(); let mut value: [f32; $N] = value.into(); + let (one, two) = self + .ui + .scratch_txt_with_opt(self.label, self.display_format); + let changed = unsafe { - sys::$igInputFloatN( - self.ui.scratch_txt(self.label), - value.as_mut_ptr(), - b"%.3f\0".as_ptr() as *const _, - self.flags.bits() as i32, - ) + sys::$igInputFloatN(one, value.as_mut_ptr(), two, self.flags.bits() as i32) }; if changed { @@ -661,6 +695,175 @@ impl_input_intn!(InputInt2, MintIVec2, 2, igInputInt2); impl_input_intn!(InputInt3, MintIVec3, 3, igInputInt3); impl_input_intn!(InputInt4, MintIVec4, 4, igInputInt4); +/// Builder for an input scalar widget. +#[must_use] +pub struct InputScalar<'ui, 'p, T, L, F = &'static str> { + value: &'p mut T, + label: L, + step: Option, + step_fast: Option, + display_format: Option, + flags: InputTextFlags, + ui: &'ui Ui, +} + +impl<'ui, 'p, L: AsRef, T: DataTypeKind> InputScalar<'ui, 'p, T, L> { + /// Constructs a new input scalar builder. + #[doc(alias = "InputScalar", alias = "InputScalarN")] + pub fn new(ui: &'ui Ui, label: L, value: &'p mut T) -> Self { + InputScalar { + value, + label, + step: None, + step_fast: None, + display_format: None, + flags: InputTextFlags::empty(), + ui, + } + } +} + +impl<'ui, 'p, L: AsRef, T: DataTypeKind, F: AsRef> InputScalar<'ui, 'p, T, L, F> { + /// Sets the display format using *a C-style printf string* + pub fn display_format>( + self, + display_format: F2, + ) -> InputScalar<'ui, 'p, T, L, F2> { + InputScalar { + value: self.value, + label: self.label, + step: self.step, + step_fast: self.step_fast, + display_format: Some(display_format), + flags: self.flags, + ui: self.ui, + } + } + /// Builds an input scalar that is bound to the given value. + /// + /// Returns true if the value was changed. + pub fn build(self, ui: &Ui) -> bool { + unsafe { + let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format); + + sys::igInputScalar( + one, + T::KIND as i32, + self.value as *mut T as *mut c_void, + self.step + .as_ref() + .map(|step| step as *const T) + .unwrap_or(ptr::null()) as *const c_void, + self.step_fast + .as_ref() + .map(|step| step as *const T) + .unwrap_or(ptr::null()) as *const c_void, + two, + self.flags.bits() as i32, + ) + } + } + + #[inline] + pub fn step(mut self, value: T) -> Self { + self.step = Some(value); + self + } + + #[inline] + pub fn step_fast(mut self, value: T) -> Self { + self.step_fast = Some(value); + self + } + + impl_text_flags!(InputScalar); +} + +/// Builder for an input scalar widget. +#[must_use] +pub struct InputScalarN<'ui, 'p, T, L, F = &'static str> { + values: &'p mut [T], + label: L, + step: Option, + step_fast: Option, + display_format: Option, + flags: InputTextFlags, + ui: &'ui Ui, +} + +impl<'ui, 'p, L: AsRef, T: DataTypeKind> InputScalarN<'ui, 'p, T, L> { + /// Constructs a new input scalar builder. + #[doc(alias = "InputScalarN")] + pub fn new(ui: &'ui Ui, label: L, values: &'p mut [T]) -> Self { + InputScalarN { + values, + label, + step: None, + step_fast: None, + display_format: None, + flags: InputTextFlags::empty(), + ui, + } + } +} + +impl<'ui, 'p, L: AsRef, T: DataTypeKind, F: AsRef> InputScalarN<'ui, 'p, T, L, F> { + /// Sets the display format using *a C-style printf string* + pub fn display_format>( + self, + display_format: F2, + ) -> InputScalarN<'ui, 'p, T, L, F2> { + InputScalarN { + values: self.values, + label: self.label, + step: self.step, + step_fast: self.step_fast, + display_format: Some(display_format), + flags: self.flags, + ui: self.ui, + } + } + /// Builds a horizontal array of multiple input scalars attached to the given slice. + /// + /// Returns true if any value was changed. + pub fn build(self, ui: &Ui) -> bool { + unsafe { + let (one, two) = ui.scratch_txt_with_opt(self.label, self.display_format); + + sys::igInputScalarN( + one, + T::KIND as i32, + self.values.as_mut_ptr() as *mut c_void, + self.values.len() as i32, + self.step + .as_ref() + .map(|step| step as *const T) + .unwrap_or(ptr::null()) as *const c_void, + self.step_fast + .as_ref() + .map(|step| step as *const T) + .unwrap_or(ptr::null()) as *const c_void, + two, + self.flags.bits() as i32, + ) + } + } + + #[inline] + pub fn step(mut self, value: T) -> Self { + self.step = Some(value); + self + } + + #[inline] + pub fn step_fast(mut self, value: T) -> Self { + self.step_fast = Some(value); + self + } + + impl_text_flags!(InputScalar); +} + bitflags!( /// Callback flags for an `InputText` widget. These correspond to /// the general textflags. diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index 4de20f7ed..90e94a516 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -551,6 +551,30 @@ impl<'ui> Ui { { InputInt4::new(self, label, value) } + #[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, + T: internal::DataTypeKind, + { + InputScalar::new(self, label, value) + } + #[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, + T: internal::DataTypeKind, + { + InputScalarN::new(self, label, values) + } } create_token!(