diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index f08300d..a43e95b 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -544,8 +544,8 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { 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(); - ColorEdit::new("color 1", &mut state.col1).build(ui); - ColorEdit::new("color 2", &mut state.col2).build(ui); + ColorEdit3::new("color 1", &mut state.col1).build(ui); + ColorEdit4::new("color 2", &mut state.col2).build(ui); TreeNode::new("Multi-component Widgets").build(ui, || { ui.input_float2("input float2", &mut state.vec2f) @@ -601,19 +601,19 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { "Click on the colored square to open a color picker. CTRL+click on individual component to input value.\n", ); - ColorEdit::new("MyColor##1", &mut s.color) + ColorEdit4::new("MyColor##1", &mut s.color) .flags(misc_flags) .alpha(false) .build(ui); ui.text("Color widget HSV with Alpha:"); - ColorEdit::new("MyColor##2", &mut s.color) + ColorEdit4::new("MyColor##2", &mut s.color) .flags(misc_flags) .input_mode(ColorEditInputMode::HSV) .build(ui); ui.text("Color widget with Float Display:"); - ColorEdit::new("MyColor##2f", &mut s.color) + ColorEdit4::new("MyColor##2f", &mut s.color) .flags(misc_flags) .format(ColorFormat::Float) .build(ui); @@ -627,7 +627,7 @@ CTRL+click on individual component to input value.\n", With the label(false) function you can pass a non-empty label which \ will only be used for the tooltip and picker popup.", ); - ColorEdit::new("MyColor##3", &mut s.color) + ColorEdit4::new("MyColor##3", &mut s.color) .flags(misc_flags) .inputs(false) .label(false) @@ -642,13 +642,13 @@ CTRL+click on individual component to input value.\n", ui.checkbox("With Ref Color", &mut s.ref_color); if s.ref_color { ui.same_line(); - ColorEdit::new("##RefColor", &mut s.ref_color_v) + ColorEdit4::new("##RefColor", &mut s.ref_color_v) .flags(misc_flags) .inputs(false) .build(ui); } } - let mut b = ColorPicker::new + let mut b = ColorPicker4::new ("MyColor##4", &mut s.color) .flags(misc_flags) .alpha(s.alpha) @@ -657,7 +657,7 @@ CTRL+click on individual component to input value.\n", .display_rgb(true); if s.ref_color { - b = b.reference_color(&s.ref_color_v) + b = b.reference_color(s.ref_color_v) } b.build(ui); }); @@ -806,7 +806,7 @@ CTRL+click on individual component to input value.\n", let items = &["aaaa", "bbbb", "cccc", "dddd", "eeee"]; ui.combo_simple_string("Combo", &mut state.stacked_modals_item, items); - ColorEdit::new("color", &mut state.stacked_modals_color).build(ui); + ColorEdit4::new("color", &mut state.stacked_modals_color).build(ui); if ui.button("Add another modal..") { ui.open_popup("Stacked 2") ; @@ -976,7 +976,7 @@ fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, .build(|| { ui.text("Primitives"); // TODO: Add DragFloat to change value of sz - ColorEdit::new("Color", &mut state.col).build(ui); + ColorEdit3::new("Color", &mut state.col).build(ui); let draw_list = ui.get_window_draw_list(); let p = ui.cursor_screen_pos(); let spacing = 8.0; diff --git a/imgui-sys/Cargo.toml b/imgui-sys/Cargo.toml index 54cd05c..2515d41 100644 --- a/imgui-sys/Cargo.toml +++ b/imgui-sys/Cargo.toml @@ -15,6 +15,7 @@ exclude = ["third-party/*.json", "third-party/*.lua", "third-party/imgui/*/"] [dependencies] chlorine = "1.0.7" +mint = "0.5.6" [build-dependencies] cc = "1.0" diff --git a/imgui-sys/src/lib.rs b/imgui-sys/src/lib.rs index d7afc7f..89535cc 100644 --- a/imgui-sys/src/lib.rs +++ b/imgui-sys/src/lib.rs @@ -71,6 +71,23 @@ impl From for (f32, f32) { } } +impl From> for ImVec2 { + fn from(o: mint::Vector2) -> Self { + Self { x: o.x, y: o.y } + } +} + +impl From> for ImVec4 { + fn from(o: mint::Vector4) -> Self { + Self { + x: o.x, + y: o.y, + z: o.z, + w: o.w, + } + } +} + impl ImVec4 { #[inline] pub const fn new(x: f32, y: f32, z: f32, w: f32) -> ImVec4 { diff --git a/imgui/Cargo.toml b/imgui/Cargo.toml index b2d5e28..b126807 100644 --- a/imgui/Cargo.toml +++ b/imgui/Cargo.toml @@ -15,6 +15,7 @@ exclude = ["/resources"] [dependencies] bitflags = "1" imgui-sys = { version = "0.8.1-alpha.0", path = "../imgui-sys" } +mint = "0.5.6" parking_lot = "0.11" [features] diff --git a/imgui/src/color.rs b/imgui/src/color.rs index 5f7e07c..1d20157 100644 --- a/imgui/src/color.rs +++ b/imgui/src/color.rs @@ -1,3 +1,5 @@ +use crate::math::MintVec4; + /// Wraps u32 that represents a packed RGBA color. Mostly used by types in the /// low level custom drawing API, such as [`DrawListMut`](crate::DrawListMut). /// @@ -220,6 +222,12 @@ impl From for ImColor32 { } } +impl From for ImColor32 { + fn from(v: MintVec4) -> Self { + Self::from_rgba_f32s(v.x, v.y, v.z, v.w) + } +} + impl From<[f32; 4]> for ImColor32 { #[inline] fn from(v: [f32; 4]) -> Self { diff --git a/imgui/src/draw_list.rs b/imgui/src/draw_list.rs index e6882e5..27323b0 100644 --- a/imgui/src/draw_list.rs +++ b/imgui/src/draw_list.rs @@ -15,7 +15,7 @@ use bitflags::bitflags; -use crate::ImColor32; +use crate::{math::MintVec2, ImColor32}; use sys::ImDrawList; use super::Ui; @@ -214,7 +214,12 @@ impl<'ui> ChannelsSplit<'ui> { impl<'ui> DrawListMut<'ui> { /// Returns a line from point `p1` to `p2` with color `c`. #[doc(alias = "AddLine")] - pub fn add_line(&'ui self, p1: [f32; 2], p2: [f32; 2], c: C) -> Line<'ui> + pub fn add_line( + &'ui self, + p1: impl Into, + p2: impl Into, + c: C, + ) -> Line<'ui> where C: Into, { @@ -224,7 +229,12 @@ impl<'ui> DrawListMut<'ui> { /// Returns a rectangle whose upper-left corner is at point `p1` /// and lower-right corner is at point `p2`, with color `c`. #[doc(alias = "AddRectFilled", alias = "AddRect")] - pub fn add_rect(&'ui self, p1: [f32; 2], p2: [f32; 2], c: C) -> Rect<'ui> + pub fn add_rect( + &'ui self, + p1: impl Into, + p2: impl Into, + c: C, + ) -> Rect<'ui> where C: Into, { @@ -239,8 +249,8 @@ impl<'ui> DrawListMut<'ui> { #[doc(alias = "AddRectFilledMultiColor")] pub fn add_rect_filled_multicolor( &self, - p1: [f32; 2], - p2: [f32; 2], + p1: impl Into, + p2: impl Into, col_upr_left: C1, col_upr_right: C2, col_bot_right: C3, @@ -254,8 +264,8 @@ impl<'ui> DrawListMut<'ui> { unsafe { sys::ImDrawList_AddRectFilledMultiColor( self.draw_list, - p1.into(), - p2.into(), + p1.into().into(), + p2.into().into(), col_upr_left.into().into(), col_upr_right.into().into(), col_bot_right.into().into(), @@ -269,9 +279,9 @@ impl<'ui> DrawListMut<'ui> { #[doc(alias = "AddTriangleFilled", alias = "AddTriangle")] pub fn add_triangle( &'ui self, - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], + p1: impl Into, + p2: impl Into, + p3: impl Into, c: C, ) -> Triangle<'ui> where @@ -282,7 +292,12 @@ impl<'ui> DrawListMut<'ui> { /// Returns a circle with the given `center`, `radius` and `color`. #[doc(alias = "AddCircleFilled", alias = "AddCircle")] - pub fn add_circle(&'ui self, center: [f32; 2], radius: f32, color: C) -> Circle<'ui> + pub fn add_circle( + &'ui self, + center: impl Into, + radius: f32, + color: C, + ) -> Circle<'ui> where C: Into, { @@ -291,35 +306,39 @@ impl<'ui> DrawListMut<'ui> { /// Draw a text whose upper-left corner is at point `pos`. #[doc(alias = "AddText")] - pub fn add_text(&self, pos: [f32; 2], col: C, text: T) - where - C: Into, - T: AsRef, - { + pub fn add_text( + &self, + pos: impl Into, + col: impl Into, + text: impl AsRef, + ) { use std::os::raw::c_char; let text = text.as_ref(); unsafe { let start = text.as_ptr() as *const c_char; let end = (start as usize + text.len()) as *const c_char; - sys::ImDrawList_AddText_Vec2(self.draw_list, pos.into(), col.into().into(), start, end) + sys::ImDrawList_AddText_Vec2( + self.draw_list, + pos.into().into(), + col.into().into(), + start, + end, + ) } } /// Returns a Bezier curve stretching from `pos0` to `pos1`, whose /// curvature is defined by `cp0` and `cp1`. #[doc(alias = "AddBezier", alias = "AddBezierCubic")] - pub fn add_bezier_curve( + pub fn add_bezier_curve( &'ui self, - pos0: [f32; 2], - cp0: [f32; 2], - cp1: [f32; 2], - pos1: [f32; 2], - color: C, - ) -> BezierCurve<'ui> - where - C: Into, - { + pos0: impl Into, + cp0: impl Into, + cp1: impl Into, + pos1: impl Into, + color: impl Into, + ) -> BezierCurve<'ui> { BezierCurve::new(self, pos0, cp0, cp1, pos1, color) } @@ -328,11 +347,18 @@ impl<'ui> DrawListMut<'ui> { /// Clip all drawings done within the closure `f` in the given /// rectangle. #[doc(alias = "PushClipRect", alias = "PopClipRect")] - pub fn with_clip_rect(&self, min: [f32; 2], max: [f32; 2], f: F) + pub fn with_clip_rect(&self, min: impl Into, max: impl Into, f: F) where F: FnOnce(), { - unsafe { sys::ImDrawList_PushClipRect(self.draw_list, min.into(), max.into(), false) } + unsafe { + sys::ImDrawList_PushClipRect( + self.draw_list, + min.into().into(), + max.into().into(), + false, + ) + } f(); unsafe { sys::ImDrawList_PopClipRect(self.draw_list) } } @@ -343,11 +369,17 @@ impl<'ui> DrawListMut<'ui> { /// rectangle. Intersect with all clipping rectangle previously on /// the stack. #[doc(alias = "PushClipRect", alias = "PopClipRect")] - pub fn with_clip_rect_intersect(&self, min: [f32; 2], max: [f32; 2], f: F) - where + pub fn with_clip_rect_intersect( + &self, + min: impl Into, + max: impl Into, + f: F, + ) where F: FnOnce(), { - unsafe { sys::ImDrawList_PushClipRect(self.draw_list, min.into(), max.into(), true) } + unsafe { + sys::ImDrawList_PushClipRect(self.draw_list, min.into().into(), max.into().into(), true) + } f(); unsafe { sys::ImDrawList_PopClipRect(self.draw_list) } } @@ -376,8 +408,8 @@ impl<'ui> DrawListMut<'ui> { pub fn add_image( &'ui self, texture_id: TextureId, - p_min: [f32; 2], - p_max: [f32; 2], + p_min: impl Into, + p_max: impl Into, ) -> Image<'_> { Image::new(self, texture_id, p_min, p_max) } @@ -388,10 +420,10 @@ impl<'ui> DrawListMut<'ui> { pub fn add_image_quad( &'ui self, texture_id: TextureId, - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], - p4: [f32; 2], + p1: impl Into, + p2: impl Into, + p3: impl Into, + p4: impl Into, ) -> ImageQuad<'_> { ImageQuad::new(self, texture_id, p1, p2, p3, p4) } @@ -400,8 +432,8 @@ impl<'ui> DrawListMut<'ui> { pub fn add_image_rounded( &'ui self, texture_id: TextureId, - p_min: [f32; 2], - p_max: [f32; 2], + p_min: impl Into, + p_max: impl Into, rounding: f32, ) -> ImageRounded<'_> { ImageRounded::new(self, texture_id, p_min, p_max, rounding) @@ -419,13 +451,18 @@ pub struct Line<'ui> { } impl<'ui> Line<'ui> { - fn new(draw_list: &'ui DrawListMut<'_>, p1: [f32; 2], p2: [f32; 2], c: C) -> Self + fn new( + draw_list: &'ui DrawListMut<'_>, + p1: impl Into, + p2: impl Into, + c: C, + ) -> Self where C: Into, { Self { - p1, - p2, + p1: p1.into().into(), + p2: p2.into().into(), color: c.into(), thickness: 1.0, draw_list, @@ -466,13 +503,18 @@ pub struct Rect<'ui> { } impl<'ui> Rect<'ui> { - fn new(draw_list: &'ui DrawListMut<'_>, p1: [f32; 2], p2: [f32; 2], c: C) -> Self + fn new( + draw_list: &'ui DrawListMut<'_>, + p1: impl Into, + p2: impl Into, + c: C, + ) -> Self where C: Into, { Self { - p1, - p2, + p1: p1.into().into(), + p2: p2.into().into(), color: c.into(), rounding: 0.0, flags: DrawFlags::ROUND_CORNERS_ALL, @@ -569,18 +611,18 @@ pub struct Triangle<'ui> { impl<'ui> Triangle<'ui> { fn new( draw_list: &'ui DrawListMut<'_>, - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], + p1: impl Into, + p2: impl Into, + p3: impl Into, c: C, ) -> Self where C: Into, { Self { - p1, - p2, - p3, + p1: p1.into().into(), + p2: p2.into().into(), + p3: p3.into().into(), color: c.into(), thickness: 1.0, filled: false, @@ -641,12 +683,17 @@ pub struct Circle<'ui> { impl<'ui> Circle<'ui> { /// Typically constructed by [`DrawListMut::add_circle`] - pub fn new(draw_list: &'ui DrawListMut<'_>, center: [f32; 2], radius: f32, color: C) -> Self + pub fn new( + draw_list: &'ui DrawListMut<'_>, + center: impl Into, + radius: f32, + color: C, + ) -> Self where C: Into, { Self { - center, + center: center.into().into(), radius, color: color.into(), num_segments: 0, @@ -720,20 +767,20 @@ impl<'ui> BezierCurve<'ui> { /// Typically constructed by [`DrawListMut::add_bezier_curve`] pub fn new( draw_list: &'ui DrawListMut<'_>, - pos0: [f32; 2], - cp0: [f32; 2], - cp1: [f32; 2], - pos1: [f32; 2], + pos0: impl Into, + cp0: impl Into, + cp1: impl Into, + pos1: impl Into, c: C, ) -> Self where C: Into, { Self { - pos0, - cp0, - cp1, - pos1, + pos0: pos0.into().into(), + cp0: cp0.into().into(), + cp1: cp1.into().into(), + pos1: pos1.into().into(), color: c.into(), thickness: 1.0, num_segments: None, @@ -789,13 +836,13 @@ impl<'ui> Image<'ui> { pub fn new( draw_list: &'ui DrawListMut<'_>, texture_id: TextureId, - p_min: [f32; 2], - p_max: [f32; 2], + p_min: impl Into, + p_max: impl Into, ) -> Self { Self { texture_id, - p_min, - p_max, + p_min: p_min.into().into(), + p_max: p_max.into().into(), uv_min: [0.0, 0.0], uv_max: [1.0, 1.0], col: [1.0, 1.0, 1.0, 1.0].into(), @@ -804,13 +851,13 @@ impl<'ui> Image<'ui> { } /// Set uv_min (default `[0.0, 0.0]`) - pub fn uv_min(mut self, uv_min: [f32; 2]) -> Self { - self.uv_min = uv_min; + pub fn uv_min(mut self, uv_min: impl Into) -> Self { + self.uv_min = uv_min.into().into(); self } /// Set uv_max (default `[1.0, 1.0]`) - pub fn uv_max(mut self, uv_max: [f32; 2]) -> Self { - self.uv_max = uv_max; + pub fn uv_max(mut self, uv_max: impl Into) -> Self { + self.uv_max = uv_max.into().into(); self } @@ -862,17 +909,17 @@ impl<'ui> ImageQuad<'ui> { pub fn new( draw_list: &'ui DrawListMut<'_>, texture_id: TextureId, - p1: [f32; 2], - p2: [f32; 2], - p3: [f32; 2], - p4: [f32; 2], + p1: impl Into, + p2: impl Into, + p3: impl Into, + p4: impl Into, ) -> Self { Self { texture_id, - p1, - p2, - p3, - p4, + p1: p1.into().into(), + p2: p2.into().into(), + p3: p3.into().into(), + p4: p4.into().into(), uv1: [0.0, 0.0], uv2: [1.0, 0.0], uv3: [1.0, 1.0], @@ -890,11 +937,17 @@ impl<'ui> ImageQuad<'ui> { /// uv3: [1, 1], /// uv4: [0, 1], /// ``` - pub fn uv(mut self, uv1: [f32; 2], uv2: [f32; 2], uv3: [f32; 2], uv4: [f32; 2]) -> Self { - self.uv1 = uv1; - self.uv2 = uv2; - self.uv3 = uv3; - self.uv4 = uv4; + pub fn uv( + mut self, + uv1: impl Into, + uv2: impl Into, + uv3: impl Into, + uv4: impl Into, + ) -> Self { + self.uv1 = uv1.into().into(); + self.uv2 = uv2.into().into(); + self.uv3 = uv3.into().into(); + self.uv4 = uv4.into().into(); self } @@ -949,14 +1002,14 @@ impl<'ui> ImageRounded<'ui> { pub fn new( draw_list: &'ui DrawListMut<'_>, texture_id: TextureId, - p_min: [f32; 2], - p_max: [f32; 2], + p_min: impl Into, + p_max: impl Into, rounding: f32, ) -> Self { Self { texture_id, - p_min, - p_max, + p_min: p_min.into().into(), + p_max: p_max.into().into(), uv_min: [0.0, 0.0], uv_max: [1.0, 1.0], col: [1.0, 1.0, 1.0, 1.0].into(), @@ -967,13 +1020,13 @@ impl<'ui> ImageRounded<'ui> { } /// Set uv_min (default `[0.0, 0.0]`) - pub fn uv_min(mut self, uv_min: [f32; 2]) -> Self { - self.uv_min = uv_min; + pub fn uv_min(mut self, uv_min: impl Into) -> Self { + self.uv_min = uv_min.into().into(); self } /// Set uv_max (default `[1.0, 1.0]`) - pub fn uv_max(mut self, uv_max: [f32; 2]) -> Self { - self.uv_max = uv_max; + pub fn uv_max(mut self, uv_max: impl Into) -> Self { + self.uv_max = uv_max.into().into(); self } diff --git a/imgui/src/input/mouse.rs b/imgui/src/input/mouse.rs index b92b3d0..7aa66ab 100644 --- a/imgui/src/input/mouse.rs +++ b/imgui/src/input/mouse.rs @@ -1,5 +1,6 @@ use std::ptr; +use crate::math::MintVec2; use crate::sys; use crate::Ui; @@ -133,8 +134,12 @@ impl<'ui> Ui<'ui> { /// /// Clipped by current clipping settings, but disregards other factors like focus, window /// ordering, modal popup blocking. - pub fn is_mouse_hovering_rect(&self, r_min: [f32; 2], r_max: [f32; 2]) -> bool { - unsafe { sys::igIsMouseHoveringRect(r_min.into(), r_max.into(), true) } + pub fn is_mouse_hovering_rect( + &self, + r_min: impl Into, + r_max: impl Into, + ) -> bool { + unsafe { sys::igIsMouseHoveringRect(r_min.into().into(), r_max.into().into(), true) } } /// Returns the mouse position backed up at the time of opening a popup #[doc(alias = "GetMousePosOnOpeningCurrentPopup")] @@ -221,8 +226,8 @@ impl<'ui> Ui<'ui> { unsafe { sys::igIsMousePosValid(ptr::null()) } } #[doc(alias = "IsMousePosValid")] - pub fn is_mouse_pos_valid(&self, mouse_pos: [f32; 2]) -> bool { - unsafe { sys::igIsMousePosValid(&mouse_pos.into()) } + pub fn is_mouse_pos_valid(&self, mouse_pos: impl Into) -> bool { + unsafe { sys::igIsMousePosValid(&mouse_pos.into().into()) } } } diff --git a/imgui/src/input_widget.rs b/imgui/src/input_widget.rs index ae6b618..200df0f 100644 --- a/imgui/src/input_widget.rs +++ b/imgui/src/input_widget.rs @@ -2,6 +2,7 @@ use bitflags::bitflags; use std::ops::Range; use std::os::raw::{c_char, c_int, c_void}; +use crate::math::*; use crate::sys; use crate::Ui; @@ -360,12 +361,12 @@ impl<'ui, 'p, L: AsRef> InputTextMultiline<'ui, 'p, L, PassthroughCallback> /// 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 { + pub fn new(ui: &'ui Ui<'ui>, label: L, buf: &'p mut String, size: impl Into) -> Self { InputTextMultiline { label, buf, flags: InputTextFlags::CALLBACK_RESIZE, - size, + size: size.into().into(), callback_handler: PassthroughCallback, ui, } @@ -552,17 +553,22 @@ impl<'ui, 'p, L: AsRef> InputFloat<'ui, 'p, L> { } macro_rules! impl_input_floatn { - ($InputFloatN:ident, $N:expr, $igInputFloatN:ident) => { + ($InputFloatN:ident, $MINT_TARGET:ty, $N:expr, $igInputFloatN:ident) => { #[must_use] - pub struct $InputFloatN<'ui, 'p, L> { + pub struct $InputFloatN<'ui, 'p, L, T> { label: L, - value: &'p mut [f32; $N], + value: &'p mut T, flags: InputTextFlags, ui: &'ui Ui<'ui>, } - impl<'ui, 'p, L: AsRef> $InputFloatN<'ui, 'p, L> { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut [f32; $N]) -> Self { + impl<'ui, 'p, L, T> $InputFloatN<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into<$MINT_TARGET>, + $MINT_TARGET: Into + Into<[f32; $N]>, + { + pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut T) -> Self { $InputFloatN { label, value, @@ -572,14 +578,24 @@ macro_rules! impl_input_floatn { } pub fn build(self) -> bool { - unsafe { + let value: $MINT_TARGET = (*self.value).into(); + let mut value: [f32; $N] = value.into(); + + let changed = unsafe { sys::$igInputFloatN( self.ui.scratch_txt(self.label), - self.value.as_mut_ptr(), + value.as_mut_ptr(), b"%.3f\0".as_ptr() as *const _, self.flags.bits() as i32, ) + }; + + if changed { + let value: $MINT_TARGET = value.into(); + *self.value = value.into(); } + + changed } impl_text_flags!($InputFloatN); @@ -587,22 +603,27 @@ macro_rules! impl_input_floatn { }; } -impl_input_floatn!(InputFloat2, 2, igInputFloat2); -impl_input_floatn!(InputFloat3, 3, igInputFloat3); -impl_input_floatn!(InputFloat4, 4, igInputFloat4); +impl_input_floatn!(InputFloat2, MintVec2, 2, igInputFloat2); +impl_input_floatn!(InputFloat3, MintVec3, 3, igInputFloat3); +impl_input_floatn!(InputFloat4, MintVec4, 4, igInputFloat4); macro_rules! impl_input_intn { - ($InputIntN:ident, $N:expr, $igInputIntN:ident) => { + ($InputIntN:ident, $MINT_TARGET:ident, $N:expr, $igInputIntN:ident) => { #[must_use] - pub struct $InputIntN<'ui, 'p, L> { + pub struct $InputIntN<'ui, 'p, L, T> { label: L, - value: &'p mut [i32; $N], + value: &'p mut T, flags: InputTextFlags, ui: &'ui Ui<'ui>, } - impl<'ui, 'p, L: AsRef> $InputIntN<'ui, 'p, L> { - pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut [i32; $N]) -> Self { + impl<'ui, 'p, L, T> $InputIntN<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into<$MINT_TARGET>, + $MINT_TARGET: Into + Into<[i32; $N]>, + { + pub fn new(ui: &'ui Ui<'ui>, label: L, value: &'p mut T) -> Self { $InputIntN { label, value, @@ -612,13 +633,23 @@ macro_rules! impl_input_intn { } pub fn build(self) -> bool { - unsafe { + let value: $MINT_TARGET = (*self.value).into(); + let mut value: [i32; $N] = value.into(); + + let changed = unsafe { sys::$igInputIntN( self.ui.scratch_txt(self.label), - self.value.as_mut_ptr(), + value.as_mut_ptr(), self.flags.bits() as i32, ) + }; + + if changed { + let value: $MINT_TARGET = value.into(); + *self.value = value.into(); } + + changed } impl_text_flags!($InputIntN); @@ -626,9 +657,9 @@ macro_rules! impl_input_intn { }; } -impl_input_intn!(InputInt2, 2, igInputInt2); -impl_input_intn!(InputInt3, 3, igInputInt3); -impl_input_intn!(InputInt4, 4, igInputInt4); +impl_input_intn!(InputInt2, MintIVec2, 2, igInputInt2); +impl_input_intn!(InputInt3, MintIVec3, 3, igInputInt3); +impl_input_intn!(InputInt4, MintIVec4, 4, igInputInt4); bitflags!( /// Callback flags for an `InputText` widget. These correspond to diff --git a/imgui/src/layout.rs b/imgui/src/layout.rs index f039b17..b0cdd16 100644 --- a/imgui/src/layout.rs +++ b/imgui/src/layout.rs @@ -1,3 +1,4 @@ +use crate::math::MintVec2; use crate::sys; use crate::Ui; @@ -64,8 +65,8 @@ impl<'ui> Ui<'ui> { /// /// Can be used to move the cursor on the window. #[doc(alias = "Dummy")] - pub fn dummy(&self, size: [f32; 2]) { - unsafe { sys::igDummy(size.into()) } + pub fn dummy(&self, size: impl Into) { + unsafe { sys::igDummy(size.into().into()) } } /// Moves content position to the right by `Style::indent_spacing` @@ -126,8 +127,8 @@ impl<'ui> Ui<'ui> { /// /// This sets the point on which the next widget will be drawn. #[doc(alias = "SetCursorPos")] - pub fn set_cursor_pos(&self, pos: [f32; 2]) { - unsafe { sys::igSetCursorPos(pos.into()) }; + pub fn set_cursor_pos(&self, pos: impl Into) { + unsafe { sys::igSetCursorPos(pos.into().into()) }; } /// Returns the initial cursor position (in window coordinates) #[doc(alias = "GetCursorStartPos")] @@ -147,8 +148,8 @@ impl<'ui> Ui<'ui> { } /// Sets the cursor position (in absolute screen coordinates) #[doc(alias = "SetCursorScreenPos")] - pub fn set_cursor_screen_pos(&self, pos: [f32; 2]) { - unsafe { sys::igSetCursorScreenPos(pos.into()) } + pub fn set_cursor_screen_pos(&self, pos: impl Into) { + unsafe { sys::igSetCursorScreenPos(pos.into().into()) } } /// Vertically aligns text baseline so that it will align properly to regularly frame items. /// diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index fa7f727..7bfca42 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -48,6 +48,7 @@ pub use self::widget::tree::*; pub use self::window::child_window::*; pub use self::window::*; use internal::RawCast; +use math::*; #[macro_use] mod string; @@ -68,6 +69,7 @@ pub mod internal; mod io; mod layout; mod list_clipper; +mod math; mod plothistogram; mod plotlines; mod popups; @@ -387,27 +389,43 @@ impl<'ui> Ui<'ui> { ) -> InputFloat<'ui, 'p, L> { InputFloat::new(self, label, value) } - pub fn input_float2<'p, L: AsRef>( + #[doc(alias = "InputFloat2")] + pub fn input_float2<'p, L, T>( &'ui self, label: L, - value: &'p mut [f32; 2], - ) -> InputFloat2<'ui, 'p, L> { + value: &'p mut T, + ) -> InputFloat2<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintVec2: Into + Into<[f32; 2]>, + { InputFloat2::new(self, label, value) } #[doc(alias = "InputFloat3")] - pub fn input_float3<'p, L: AsRef>( + pub fn input_float3<'p, L, T>( &'ui self, label: L, - value: &'p mut [f32; 3], - ) -> InputFloat3<'ui, 'p, L> { + value: &'p mut T, + ) -> InputFloat3<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintVec3: Into + Into<[f32; 3]>, + { InputFloat3::new(self, label, value) } #[doc(alias = "InputFloat4")] - pub fn input_float4<'p, L: AsRef>( + pub fn input_float4<'p, L, T>( &'ui self, label: L, - value: &'p mut [f32; 4], - ) -> InputFloat4<'ui, 'p, L> { + value: &'p mut T, + ) -> InputFloat4<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintVec4: Into + Into<[f32; 4]>, + { InputFloat4::new(self, label, value) } #[doc(alias = "InputInt")] @@ -419,27 +437,30 @@ impl<'ui> Ui<'ui> { InputInt::new(self, label, value) } #[doc(alias = "InputInt2")] - pub fn input_int2<'p, L: AsRef>( - &'ui self, - label: L, - value: &'p mut [i32; 2], - ) -> InputInt2<'ui, 'p, L> { + pub fn input_int2<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt2<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintIVec2: Into + Into<[i32; 2]>, + { InputInt2::new(self, label, value) } #[doc(alias = "InputInt3")] - pub fn input_int3<'p, L: AsRef>( - &'ui self, - label: L, - value: &'p mut [i32; 3], - ) -> InputInt3<'ui, 'p, L> { + pub fn input_int3<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt3<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintIVec3: Into + Into<[i32; 3]>, + { InputInt3::new(self, label, value) } #[doc(alias = "InputInt4")] - pub fn input_int4<'p, L: AsRef>( - &'ui self, - label: L, - value: &'p mut [i32; 4], - ) -> InputInt4<'ui, 'p, L> { + pub fn input_int4<'p, L, T>(&'ui self, label: L, value: &'p mut T) -> InputInt4<'ui, 'p, L, T> + where + L: AsRef, + T: Copy + Into, + MintIVec4: Into + Into<[i32; 4]>, + { InputInt4::new(self, label, value) } } diff --git a/imgui/src/math.rs b/imgui/src/math.rs new file mode 100644 index 0000000..7f8ab0d --- /dev/null +++ b/imgui/src/math.rs @@ -0,0 +1,7 @@ +pub(crate) type MintVec2 = mint::Vector2; +pub(crate) type MintVec3 = mint::Vector3; +pub(crate) type MintVec4 = mint::Vector4; + +pub(crate) type MintIVec2 = mint::Vector2; +pub(crate) type MintIVec3 = mint::Vector3; +pub(crate) type MintIVec4 = mint::Vector4; diff --git a/imgui/src/plothistogram.rs b/imgui/src/plothistogram.rs index ef490a1..0822970 100644 --- a/imgui/src/plothistogram.rs +++ b/imgui/src/plothistogram.rs @@ -62,8 +62,8 @@ impl<'ui, 'p, Label: AsRef, Overlay: AsRef> PlotHistogram<'ui, 'p, Lab self } - pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self { - self.graph_size = graph_size; + pub fn graph_size(mut self, graph_size: impl Into) -> Self { + self.graph_size = graph_size.into().into(); self } diff --git a/imgui/src/plotlines.rs b/imgui/src/plotlines.rs index 5c57e8e..a4d8441 100644 --- a/imgui/src/plotlines.rs +++ b/imgui/src/plotlines.rs @@ -62,8 +62,8 @@ impl<'ui, 'p, Label: AsRef, Overlay: AsRef> PlotLines<'ui, 'p, Label, self } - pub fn graph_size(mut self, graph_size: [f32; 2]) -> Self { - self.graph_size = graph_size; + pub fn graph_size(mut self, graph_size: impl Into) -> Self { + self.graph_size = graph_size.into().into(); self } diff --git a/imgui/src/render/draw_data.rs b/imgui/src/render/draw_data.rs index 0bd3e49..56fed63 100644 --- a/imgui/src/render/draw_data.rs +++ b/imgui/src/render/draw_data.rs @@ -1,6 +1,7 @@ use std::slice; use crate::internal::{RawCast, RawWrapper}; +use crate::math::MintVec2; use crate::render::renderer::TextureId; use crate::sys; @@ -72,7 +73,7 @@ impl DrawData { /// Can be used if your final output buffer is at a different scale than imgui-rs expects, or /// if there is a difference between your window resolution and framebuffer resolution. #[doc(alias = "ScaleClipRects")] - pub fn scale_clip_rects(&mut self, fb_scale: [f32; 2]) { + pub fn scale_clip_rects(&mut self, fb_scale: MintVec2) { unsafe { sys::ImDrawData_ScaleClipRects(self.raw_mut(), fb_scale.into()); } diff --git a/imgui/src/stacks.rs b/imgui/src/stacks.rs index c5964a7..94fad58 100644 --- a/imgui/src/stacks.rs +++ b/imgui/src/stacks.rs @@ -5,6 +5,7 @@ use std::ptr; use crate::context::Context; use crate::fonts::atlas::FontId; use crate::internal::RawCast; +use crate::math::MintVec4; use crate::style::{StyleColor, StyleVar}; use crate::sys; use crate::{Id, Ui}; @@ -61,9 +62,9 @@ impl<'ui> Ui<'ui> { pub fn push_style_color( &self, style_color: StyleColor, - color: [f32; 4], + color: impl Into, ) -> ColorStackToken<'_> { - unsafe { sys::igPushStyleColor_Vec4(style_color as i32, color.into()) }; + unsafe { sys::igPushStyleColor_Vec4(style_color as i32, color.into().into()) }; ColorStackToken::new(self) } diff --git a/imgui/src/utils.rs b/imgui/src/utils.rs index a1f41e1..b977c6d 100644 --- a/imgui/src/utils.rs +++ b/imgui/src/utils.rs @@ -2,8 +2,10 @@ use bitflags::bitflags; use crate::input::mouse::MouseButton; -use crate::style::{Style, StyleColor}; +use crate::math::MintVec2; +use crate::style::StyleColor; use crate::sys; +use crate::Style; use crate::Ui; bitflags! { @@ -143,13 +145,17 @@ impl<'ui> Ui<'ui> { impl<'ui> Ui<'ui> { /// Returns `true` if the rectangle (of given size, starting from cursor position) is visible #[doc(alias = "IsRectVisibleNil")] - pub fn is_cursor_rect_visible(&self, size: [f32; 2]) -> bool { - unsafe { sys::igIsRectVisible_Nil(size.into()) } + pub fn is_cursor_rect_visible(&self, size: impl Into) -> bool { + unsafe { sys::igIsRectVisible_Nil(size.into().into()) } } /// Returns `true` if the rectangle (in screen coordinates) is visible #[doc(alias = "IsRectVisibleNilVec2")] - pub fn is_rect_visible(&self, rect_min: [f32; 2], rect_max: [f32; 2]) -> bool { - unsafe { sys::igIsRectVisible_Vec2(rect_min.into(), rect_max.into()) } + pub fn is_rect_visible( + &self, + rect_min: impl Into, + rect_max: impl Into, + ) -> bool { + unsafe { sys::igIsRectVisible_Vec2(rect_min.into().into(), rect_max.into().into()) } } /// Returns the global imgui-rs time. /// @@ -173,6 +179,7 @@ impl<'ui> Ui<'ui> { pub fn style_color(&self, style_color: StyleColor) -> [f32; 4] { self.ctx.style()[style_color] } + /// Returns a shared reference to the current [`Style`]. /// /// ## Safety diff --git a/imgui/src/widget/color_editors.rs b/imgui/src/widget/color_editors.rs index 0790634..e7157a5 100644 --- a/imgui/src/widget/color_editors.rs +++ b/imgui/src/widget/color_editors.rs @@ -1,41 +1,44 @@ use bitflags::bitflags; use std::ptr; +use crate::math::MintVec2; +use crate::math::MintVec3; +use crate::math::MintVec4; use crate::sys; use crate::Ui; -/// Mutable reference to an editable color value. -#[derive(Debug)] -pub enum EditableColor<'a> { - /// Color value with three float components (e.g. RGB). - Float3(&'a mut [f32; 3]), - /// Color value with four float components (e.g. RGBA). - Float4(&'a mut [f32; 4]), -} +// /// Mutable reference to an editable color value. +// #[derive(Debug)] +// pub enum EditableColor<'a, T> { +// /// Color value with three float components (e.g. RGB). +// Float3(&'a mut T), +// /// Color value with four float components (e.g. RGBA). +// Float4(&'a mut T), +// } -impl<'a> EditableColor<'a> { - /// Returns an unsafe mutable pointer to the color slice's buffer. - fn as_mut_ptr(&mut self) -> *mut f32 { - match *self { - EditableColor::Float3(ref mut value) => value.as_mut_ptr(), - EditableColor::Float4(ref mut value) => value.as_mut_ptr(), - } - } -} +// impl<'a> EditableColor<'a> { +// /// Returns an unsafe mutable pointer to the color slice's buffer. +// fn as_mut_ptr(&mut self) -> *mut f32 { +// match *self { +// EditableColor::Float3(ref mut value) => value.as_mut_ptr(), +// EditableColor::Float4(ref mut value) => value.as_mut_ptr(), +// } +// } +// } -impl<'a> From<&'a mut [f32; 3]> for EditableColor<'a> { - #[inline] - fn from(value: &'a mut [f32; 3]) -> EditableColor<'a> { - EditableColor::Float3(value) - } -} +// impl<'a> From<&'a mut [f32; 3]> for EditableColor<'a> { +// #[inline] +// fn from(value: &'a mut [f32; 3]) -> EditableColor<'a> { +// EditableColor::Float3(value) +// } +// } -impl<'a> From<&'a mut [f32; 4]> for EditableColor<'a> { - #[inline] - fn from(value: &'a mut [f32; 4]) -> EditableColor<'a> { - EditableColor::Float4(value) - } -} +// impl<'a> From<&'a mut [f32; 4]> for EditableColor<'a> { +// #[inline] +// fn from(value: &'a mut [f32; 4]) -> EditableColor<'a> { +// EditableColor::Float4(value) +// } +// } /// Color editor input mode. #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -176,26 +179,31 @@ bitflags! { /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(); /// # let mut color = [0.0, 0.0, 0.0, 1.0]; -/// let ce = ColorEdit::new(im_str!("color_edit"), &mut color); +/// let ce = ColorEdit4::new("color_edit", &mut color); /// if ce.build(&ui) { /// println!("The color was changed"); /// } /// ``` #[derive(Debug)] #[must_use] -pub struct ColorEdit<'a, T: AsRef + 'a> { +pub struct ColorEdit3<'a, T, C> { label: T, - value: EditableColor<'a>, + value: &'a mut C, flags: ColorEditFlags, } -impl<'a, T: AsRef + 'a> ColorEdit<'a, T> { +impl<'a, T, C> ColorEdit3<'a, T, C> +where + T: AsRef, + C: Copy + Into, + MintVec3: Into + Into<[f32; 3]>, +{ /// Constructs a new color editor builder. - #[doc(alias = "ColorEdit3", alias = "ColorEdit4")] - pub fn new(label: T, value: impl Into>) -> ColorEdit<'a, T> { - ColorEdit { + #[doc(alias = "ColorEdit3")] + pub fn new(label: T, value: &'a mut C) -> Self { + ColorEdit3 { label, - value: value.into(), + value, flags: ColorEditFlags::empty(), } } @@ -319,26 +327,208 @@ impl<'a, T: AsRef + 'a> ColorEdit<'a, T> { /// /// Returns true if the color value was changed. pub fn build(mut self, ui: &Ui<'_>) -> bool { - if let EditableColor::Float3(_) = self.value { - self.flags.insert(ColorEditFlags::NO_ALPHA); + // if let EditableColor::Float3(_) = self.value { + self.flags.insert(ColorEditFlags::NO_ALPHA); + + let as_vec3: MintVec3 = (*self.value).into(); + let mut as_vec3: [f32; 3] = as_vec3.into(); + + let changed = unsafe { + sys::igColorEdit3( + ui.scratch_txt(self.label), + as_vec3.as_mut_ptr(), + self.flags.bits() as _, + ) + }; + + // and go backwards... + if changed { + let as_vec3: MintVec3 = as_vec3.into(); + + *self.value = as_vec3.into(); } - match self.value { - EditableColor::Float3(value) => unsafe { - sys::igColorEdit3( - ui.scratch_txt(self.label), - value.as_mut_ptr(), - self.flags.bits() as _, - ) - }, - EditableColor::Float4(value) => unsafe { - sys::igColorEdit4( - ui.scratch_txt(self.label), - value.as_mut_ptr(), - self.flags.bits() as _, - ) - }, + + changed + } +} + +/// Builder for a color editor widget. +/// +/// # Examples +/// +/// ```no_run +/// # use imgui::*; +/// # let mut imgui = Context::create(); +/// # let ui = imgui.frame(); +/// # let mut color = [0.0, 0.0, 0.0, 1.0]; +/// let ce = ColorEdit4::new("color_edit", &mut color); +/// if ce.build(&ui) { +/// println!("The color was changed"); +/// } +/// ``` +#[derive(Debug)] +#[must_use] +pub struct ColorEdit4<'a, T, C> { + label: T, + value: &'a mut C, + flags: ColorEditFlags, +} + +impl<'a, T, C> ColorEdit4<'a, T, C> +where + T: AsRef, + C: Copy + Into, + MintVec4: Into + Into<[f32; 4]>, +{ + /// Constructs a new color editor builder. + #[doc(alias = "ColorEdit4")] + pub fn new(label: T, value: &'a mut C) -> Self { + Self { + label, + value, + flags: ColorEditFlags::empty(), } } + /// Replaces all current settings with the given flags. + #[inline] + pub fn flags(mut self, flags: ColorEditFlags) -> Self { + self.flags = flags; + self + } + /// Enables/disables the use of the alpha component. + #[inline] + pub fn alpha(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_ALPHA, !value); + self + } + /// Enables/disables the picker that appears when clicking on colored square. + #[inline] + pub fn picker(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_PICKER, !value); + self + } + /// Enables/disables toggling of the options menu when right-clicking on inputs or the small + /// preview. + #[inline] + pub fn options(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_OPTIONS, !value); + self + } + /// Enables/disables the colored square preview next to the inputs. + #[inline] + pub fn small_preview(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_SMALL_PREVIEW, !value); + self + } + /// Enables/disables the input sliders/text widgets. + #[inline] + pub fn inputs(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_INPUTS, !value); + self + } + /// Enables/disables the tooltip that appears when hovering the preview. + #[inline] + pub fn tooltip(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_TOOLTIP, !value); + self + } + /// Enables/disables display of the inline text label (the label is in any case forwarded to + /// the tooltip and picker). + #[inline] + pub fn label(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_LABEL, !value); + self + } + /// Enables/disables the vertical alpha bar/gradient in the color picker. + #[inline] + pub fn alpha_bar(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::ALPHA_BAR, value); + self + } + /// Sets the preview style. + #[inline] + pub fn preview(mut self, preview: ColorPreview) -> Self { + self.flags.set( + ColorEditFlags::ALPHA_PREVIEW_HALF, + preview == ColorPreview::HalfAlpha, + ); + self.flags.set( + ColorEditFlags::ALPHA_PREVIEW, + preview == ColorPreview::Alpha, + ); + self + } + /// (WIP) Currently only disables 0.0..1.0 limits in RGBA edition. + /// + /// Note: you probably want to use ColorFormat::Float as well. + #[inline] + pub fn hdr(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::HDR, value); + self + } + /// Sets the data format for input and output data. + #[inline] + pub fn input_mode(mut self, input_mode: ColorEditInputMode) -> Self { + self.flags.set( + ColorEditFlags::INPUT_RGB, + input_mode == ColorEditInputMode::RGB, + ); + self.flags.set( + ColorEditFlags::INPUT_HSV, + input_mode == ColorEditInputMode::HSV, + ); + self + } + /// Sets the color editor display mode. + #[inline] + pub fn display_mode(mut self, mode: ColorEditDisplayMode) -> Self { + self.flags.set( + ColorEditFlags::DISPLAY_RGB, + mode == ColorEditDisplayMode::RGB, + ); + self.flags.set( + ColorEditFlags::DISPLAY_HSV, + mode == ColorEditDisplayMode::HSV, + ); + self.flags.set( + ColorEditFlags::DISPLAY_HEX, + mode == ColorEditDisplayMode::HEX, + ); + self + } + /// Sets the formatting style of color components. + #[inline] + pub fn format(mut self, format: ColorFormat) -> Self { + self.flags + .set(ColorEditFlags::UINT8, format == ColorFormat::U8); + self.flags + .set(ColorEditFlags::FLOAT, format == ColorFormat::Float); + self + } + /// Builds the color editor. + /// + /// Returns true if the color value was changed. + pub fn build(self, ui: &Ui<'_>) -> bool { + let as_vec4: MintVec4 = (*self.value).into(); + let mut as_vec4: [f32; 4] = as_vec4.into(); + + let changed = unsafe { + sys::igColorEdit4( + ui.scratch_txt(self.label), + as_vec4.as_mut_ptr(), + self.flags.bits() as _, + ) + }; + + // and go backwards... + if changed { + let as_vec4: MintVec4 = as_vec4.into(); + + *self.value = as_vec4.into(); + } + + changed + } } /// Builder for a color picker widget. @@ -350,27 +540,216 @@ impl<'a, T: AsRef + 'a> ColorEdit<'a, T> { /// # let mut imgui = Context::create(); /// # let ui = imgui.frame(); /// # let mut color = [0.0, 0.0, 0.0, 1.0]; -/// let cp = ColorPicker::new(im_str!("color_picker"), &mut color); +/// let cp = ColorPicker4::new("color_picker", &mut color); /// if cp.build(&ui) { /// println!("A color was picked"); /// } /// ``` #[derive(Debug)] #[must_use] -pub struct ColorPicker<'a, T: AsRef + 'a> { - label: T, - value: EditableColor<'a>, +pub struct ColorPicker3<'a, Label, Color> { + label: Label, + value: &'a mut Color, flags: ColorEditFlags, - ref_color: Option<&'a [f32; 4]>, } -impl<'a, T: AsRef> ColorPicker<'a, T> { +impl<'a, Label, Color> ColorPicker3<'a, Label, Color> +where + Label: AsRef, + Color: Copy + Into, + MintVec3: Into + Into<[f32; 3]>, +{ /// Constructs a new color picker builder. - #[doc(alias = "ColorButton")] - pub fn new(label: T, value: impl Into>) -> Self { - ColorPicker { + #[doc(alias = "ColorPicker3")] + pub fn new(label: Label, value: &'a mut Color) -> Self { + ColorPicker3 { label, - value: value.into(), + value, + flags: ColorEditFlags::empty(), + } + } + /// Replaces all current settings with the given flags. + #[inline] + pub fn flags(mut self, flags: ColorEditFlags) -> Self { + self.flags = flags; + self + } + /// Enables/disables the use of the alpha component. + #[inline] + pub fn alpha(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_ALPHA, !value); + self + } + /// Enables/disables toggling of the options menu when right-clicking on inputs or the small + /// preview. + #[inline] + pub fn options(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_OPTIONS, !value); + self + } + /// Enables/disables the colored square preview next to the inputs. + #[inline] + pub fn small_preview(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_SMALL_PREVIEW, !value); + self + } + /// Enables/disables the input sliders/text widgets. + #[inline] + pub fn inputs(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_INPUTS, !value); + self + } + /// Enables/disables the tooltip that appears when hovering the preview. + #[inline] + pub fn tooltip(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_TOOLTIP, !value); + self + } + /// Enables/disables display of the inline text label (the label is in any case forwarded to + /// the tooltip and picker). + #[inline] + pub fn label(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_LABEL, !value); + self + } + /// Enables/disables the bigger color preview on the right side of the picker. + #[inline] + pub fn side_preview(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::NO_SIDE_PREVIEW, !value); + self + } + /// Enables/disables the vertical alpha bar/gradient in the color picker. + #[inline] + pub fn alpha_bar(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::ALPHA_BAR, value); + self + } + /// Sets the preview style. + #[inline] + pub fn preview(mut self, preview: ColorPreview) -> Self { + self.flags.set( + ColorEditFlags::ALPHA_PREVIEW_HALF, + preview == ColorPreview::HalfAlpha, + ); + self.flags.set( + ColorEditFlags::ALPHA_PREVIEW, + preview == ColorPreview::Alpha, + ); + self + } + /// Sets the data format for input and output data. + #[inline] + pub fn input_mode(mut self, input_mode: ColorEditInputMode) -> Self { + self.flags.set( + ColorEditFlags::INPUT_RGB, + input_mode == ColorEditInputMode::RGB, + ); + self.flags.set( + ColorEditFlags::INPUT_HSV, + input_mode == ColorEditInputMode::HSV, + ); + self + } + /// Enables/disables displaying the value as RGB. + #[inline] + pub fn display_rgb(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::DISPLAY_RGB, value); + self + } + /// Enables/disables displaying the value as HSV. + #[inline] + pub fn display_hsv(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::DISPLAY_HSV, value); + self + } + /// Enables/disables displaying the value as hex. + #[inline] + pub fn display_hex(mut self, value: bool) -> Self { + self.flags.set(ColorEditFlags::DISPLAY_HEX, value); + self + } + /// Sets the hue/saturation/value editor mode. + #[inline] + pub fn mode(mut self, mode: ColorPickerMode) -> Self { + self.flags.set( + ColorEditFlags::PICKER_HUE_BAR, + mode == ColorPickerMode::HueBar, + ); + self.flags.set( + ColorEditFlags::PICKER_HUE_WHEEL, + mode == ColorPickerMode::HueWheel, + ); + self + } + /// Sets the formatting style of color components. + #[inline] + pub fn format(mut self, format: ColorFormat) -> Self { + self.flags + .set(ColorEditFlags::UINT8, format == ColorFormat::U8); + self.flags + .set(ColorEditFlags::FLOAT, format == ColorFormat::Float); + self + } + + /// Builds the color picker. + /// + /// Returns true if the color value was changed. + pub fn build(mut self, ui: &Ui<'_>) -> bool { + self.flags.insert(ColorEditFlags::NO_ALPHA); + let mut value: [f32; 3] = (*self.value).into().into(); + let changed = unsafe { + sys::igColorPicker3( + ui.scratch_txt(self.label), + value.as_mut_ptr(), + self.flags.bits() as _, + ) + }; + + if changed { + let as_vec3: MintVec3 = value.into(); + + *self.value = as_vec3.into(); + } + + changed + } +} + +// Builder for a color picker widget. +/// +/// # Examples +/// +/// ```no_run +/// # use imgui::*; +/// # let mut imgui = Context::create(); +/// # let ui = imgui.frame(); +/// # let mut color = [0.0, 0.0, 0.0, 1.0]; +/// let cp = ColorPicker4::new("color_picker", &mut color); +/// if cp.build(&ui) { +/// println!("A color was picked"); +/// } +/// ``` +#[derive(Debug)] +#[must_use] +pub struct ColorPicker4<'a, Label, Color> { + label: Label, + value: &'a mut Color, + flags: ColorEditFlags, + ref_color: Option<[f32; 4]>, +} + +impl<'a, Label, Color> ColorPicker4<'a, Label, Color> +where + Label: AsRef, + Color: Copy + Into, + MintVec4: Into + Into<[f32; 4]>, +{ + /// Constructs a new color picker builder. + #[doc(alias = "ColorPicker4")] + pub fn new(label: Label, value: &'a mut Color) -> Self { + Self { + label, + value, flags: ColorEditFlags::empty(), ref_color: None, } @@ -499,26 +878,35 @@ impl<'a, T: AsRef> ColorPicker<'a, T> { } /// Sets the shown reference color. #[inline] - pub fn reference_color(mut self, ref_color: &'a [f32; 4]) -> Self { - self.ref_color = Some(ref_color); + pub fn reference_color(mut self, ref_color: impl Into) -> Self { + self.ref_color = Some(ref_color.into().into()); self } + /// Builds the color picker. /// /// Returns true if the color value was changed. pub fn build(mut self, ui: &Ui<'_>) -> bool { - if let EditableColor::Float3(_) = self.value { - self.flags.insert(ColorEditFlags::NO_ALPHA); - } + self.flags.insert(ColorEditFlags::NO_ALPHA); + let mut value: [f32; 4] = (*self.value).into().into(); let ref_color = self.ref_color.map(|c| c.as_ptr()).unwrap_or(ptr::null()); - unsafe { + + let changed = unsafe { sys::igColorPicker4( ui.scratch_txt(self.label), - self.value.as_mut_ptr(), + value.as_mut_ptr(), self.flags.bits() as _, ref_color, ) + }; + + if changed { + let as_vec3: MintVec4 = value.into(); + + *self.value = as_vec3.into(); } + + changed } } @@ -544,10 +932,10 @@ pub struct ColorButton { impl> ColorButton { /// Constructs a new color button builder. - pub fn new(desc_id: T, color: [f32; 4]) -> Self { + pub fn new(desc_id: T, color: impl Into) -> Self { ColorButton { desc_id, - color, + color: color.into().into(), flags: ColorEditFlags::empty(), size: [0.0, 0.0], } @@ -614,8 +1002,8 @@ impl> ColorButton { /// /// Use 0.0 for width and/or height to use the default size. #[inline] - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Builds the color button. diff --git a/imgui/src/widget/image.rs b/imgui/src/widget/image.rs index dd4c58b..4e2d115 100644 --- a/imgui/src/widget/image.rs +++ b/imgui/src/widget/image.rs @@ -1,5 +1,7 @@ use std::os::raw::c_void; +use crate::math::MintVec2; +use crate::math::MintVec4; use crate::render::renderer::TextureId; use crate::sys; use crate::Ui; @@ -19,10 +21,10 @@ pub struct Image { impl Image { /// Creates a new image builder with the given texture and size #[doc(alias = "Image")] - pub const fn new(texture_id: TextureId, size: [f32; 2]) -> Image { + pub fn new(texture_id: TextureId, size: impl Into) -> Image { Image { texture_id, - size, + size: size.into().into(), uv0: [0.0, 0.0], uv1: [1.0, 1.0], tint_col: [1.0, 1.0, 1.0, 1.0], @@ -30,28 +32,29 @@ impl Image { } } /// Sets the image size - pub const fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + #[deprecated(note = "just set the size in the `new` constructor.")] + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Sets uv0 (default `[0.0, 0.0]`) - pub const fn uv0(mut self, uv0: [f32; 2]) -> Self { - self.uv0 = uv0; + pub fn uv0(mut self, uv0: impl Into) -> Self { + self.uv0 = uv0.into().into(); self } /// Sets uv1 (default `[1.0, 1.0]`) - pub const fn uv1(mut self, uv1: [f32; 2]) -> Self { - self.uv1 = uv1; + pub fn uv1(mut self, uv1: impl Into) -> Self { + self.uv1 = uv1.into().into(); self } /// Sets the tint color (default: no tint color) - pub const fn tint_col(mut self, tint_col: [f32; 4]) -> Self { - self.tint_col = tint_col; + pub fn tint_col(mut self, tint_col: impl Into) -> Self { + self.tint_col = tint_col.into().into(); self } /// Sets the border color (default: no border) - pub const fn border_col(mut self, border_col: [f32; 4]) -> Self { - self.border_col = border_col; + pub fn border_col(mut self, border_col: impl Into) -> Self { + self.border_col = border_col.into().into(); self } /// Builds the image @@ -85,10 +88,10 @@ pub struct ImageButton { impl ImageButton { /// Creates a new image button builder with the given texture and size #[doc(alias = "ImageButton")] - pub fn new(texture_id: TextureId, size: [f32; 2]) -> ImageButton { + pub fn new(texture_id: TextureId, size: impl Into) -> ImageButton { ImageButton { texture_id, - size, + size: size.into().into(), uv0: [0.0, 0.0], uv1: [1.0, 1.0], frame_padding: -1, @@ -96,19 +99,21 @@ impl ImageButton { tint_col: [1.0, 1.0, 1.0, 1.0], } } + /// Sets the image button size - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + #[deprecated(note = "just set the size in the `new` constructor.")] + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Sets uv0 (default `[0.0, 0.0]`) - pub fn uv0(mut self, uv0: [f32; 2]) -> Self { - self.uv0 = uv0; + pub fn uv0(mut self, uv0: impl Into) -> Self { + self.uv0 = uv0.into().into(); self } /// Sets uv1 (default `[1.0, 1.0]`) - pub fn uv1(mut self, uv1: [f32; 2]) -> Self { - self.uv1 = uv1; + pub fn uv1(mut self, uv1: impl Into) -> Self { + self.uv1 = uv1.into().into(); self } /// Sets the frame padding (default: uses frame padding from style). @@ -121,13 +126,13 @@ impl ImageButton { self } /// Sets the background color (default: no background color) - pub fn background_col(mut self, bg_col: [f32; 4]) -> Self { - self.bg_col = bg_col; + pub fn background_col(mut self, bg_col: impl Into) -> Self { + self.bg_col = bg_col.into().into(); self } /// Sets the tint color (default: no tint color) - pub fn tint_col(mut self, tint_col: [f32; 4]) -> Self { - self.tint_col = tint_col; + pub fn tint_col(mut self, tint_col: impl Into) -> Self { + self.tint_col = tint_col.into().into(); self } /// Builds the image button diff --git a/imgui/src/widget/list_box.rs b/imgui/src/widget/list_box.rs index 0485e6d..922d871 100644 --- a/imgui/src/widget/list_box.rs +++ b/imgui/src/widget/list_box.rs @@ -8,7 +8,7 @@ use crate::Ui; #[must_use] pub struct ListBox { label: T, - size: sys::ImVec2, + size: [f32; 2], } impl> ListBox { @@ -17,7 +17,7 @@ impl> ListBox { pub fn new(label: T) -> ListBox { ListBox { label, - size: sys::ImVec2::zero(), + size: [0.0, 0.0], } } @@ -28,8 +28,8 @@ impl> ListBox { /// /// Default: [0.0, 0.0], in which case the combobox calculates a sensible width and height #[inline] - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = sys::ImVec2::new(size[0], size[1]); + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Creates a list box and starts appending to it. @@ -40,7 +40,8 @@ impl> ListBox { /// Returns `None` if the list box is not open and no content should be rendered. #[must_use] pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option> { - let should_render = unsafe { sys::igBeginListBox(ui.scratch_txt(self.label), self.size) }; + let should_render = + unsafe { sys::igBeginListBox(ui.scratch_txt(self.label), self.size.into()) }; if should_render { Some(ListBoxToken::new(ui)) } else { diff --git a/imgui/src/widget/misc.rs b/imgui/src/widget/misc.rs index e54e678..f79e128 100644 --- a/imgui/src/widget/misc.rs +++ b/imgui/src/widget/misc.rs @@ -1,6 +1,7 @@ use bitflags::bitflags; use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not}; +use crate::math::MintVec2; use crate::sys; use crate::{Direction, Ui}; @@ -38,8 +39,8 @@ impl<'ui> Ui<'ui> { /// Setting `size` as `[0.0, 0.0]` will size the button to the label's width in /// the current style. #[doc(alias = "Button")] - pub fn button_with_size(&self, label: impl AsRef, size: [f32; 2]) -> bool { - unsafe { sys::igButton(self.scratch_txt(label), size.into()) } + pub fn button_with_size(&self, label: impl AsRef, size: impl Into) -> bool { + unsafe { sys::igButton(self.scratch_txt(label), size.into().into()) } } /// Renders a small clickable button that is easy to embed in text. /// @@ -52,8 +53,8 @@ impl<'ui> Ui<'ui> { /// /// Returns true if this button was clicked. #[doc(alias = "InvisibleButton")] - pub fn invisible_button(&self, id: impl AsRef, size: [f32; 2]) -> bool { - unsafe { sys::igInvisibleButton(self.scratch_txt(id), size.into(), 0) } + pub fn invisible_button(&self, id: impl AsRef, size: impl Into) -> bool { + unsafe { sys::igInvisibleButton(self.scratch_txt(id), size.into().into(), 0) } } /// Renders a widget with button behaviour without the visual look. /// @@ -62,10 +63,16 @@ impl<'ui> Ui<'ui> { pub fn invisible_button_flags( &self, id: impl AsRef, - size: [f32; 2], + size: impl Into, flags: ButtonFlags, ) -> bool { - unsafe { sys::igInvisibleButton(self.scratch_txt(id), size.into(), flags.bits() as i32) } + unsafe { + sys::igInvisibleButton( + self.scratch_txt(id), + size.into().into(), + flags.bits() as i32, + ) + } } /// Renders a square button with an arrow shape. /// diff --git a/imgui/src/widget/progress_bar.rs b/imgui/src/widget/progress_bar.rs index dd6cba2..eb641ef 100644 --- a/imgui/src/widget/progress_bar.rs +++ b/imgui/src/widget/progress_bar.rs @@ -1,3 +1,4 @@ +use crate::math::MintVec2; use crate::sys; // use crate::ImStr; use crate::Ui; @@ -55,8 +56,8 @@ impl> ProgressBar { /// Negative values will automatically align to the end of the axis, zero will let the progress /// bar choose a size, and positive values will use the given size. #[inline] - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } diff --git a/imgui/src/widget/selectable.rs b/imgui/src/widget/selectable.rs index ef0c172..48eceaa 100644 --- a/imgui/src/widget/selectable.rs +++ b/imgui/src/widget/selectable.rs @@ -1,5 +1,6 @@ use bitflags::bitflags; +use crate::math::MintVec2; use crate::sys; use crate::Ui; @@ -100,8 +101,8 @@ impl> Selectable { /// - `> 0.0`: use given height /// - `= 0.0`: use label height #[inline] - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Builds the selectable. diff --git a/imgui/src/widget/slider.rs b/imgui/src/widget/slider.rs index 231dd6b..5b7d1c9 100644 --- a/imgui/src/widget/slider.rs +++ b/imgui/src/widget/slider.rs @@ -2,6 +2,7 @@ use bitflags::bitflags; use std::os::raw::c_void; use crate::internal::DataTypeKind; +use crate::math::MintVec2; use crate::sys; use crate::Ui; @@ -161,10 +162,10 @@ where /// It is safe, though up to C++ Dear ImGui, on how to handle when /// `min > max`. #[doc(alias = "VSliderScalar")] - pub fn new(label: Label, size: [f32; 2], min: Data, max: Data) -> Self { + pub fn new(label: Label, size: impl Into, min: Data, max: Data) -> Self { VerticalSlider { label, - size, + size: size.into().into(), min, max, display_format: None, diff --git a/imgui/src/widget/text.rs b/imgui/src/widget/text.rs index 7273ec4..99bb0d4 100644 --- a/imgui/src/widget/text.rs +++ b/imgui/src/widget/text.rs @@ -1,5 +1,6 @@ use std::os::raw::c_char; +use crate::math::MintVec4; // use crate::string::ImStr; use crate::style::StyleColor; use crate::Ui; @@ -24,7 +25,7 @@ impl<'ui> Ui<'ui> { } } /// Renders simple text using the given text color - pub fn text_colored>(&self, color: [f32; 4], text: T) { + pub fn text_colored>(&self, color: impl Into, text: T) { let style = self.push_style_color(StyleColor::Text, color); self.text(text); style.end(); diff --git a/imgui/src/window/child_window.rs b/imgui/src/window/child_window.rs index 741c657..8b83df4 100644 --- a/imgui/src/window/child_window.rs +++ b/imgui/src/window/child_window.rs @@ -1,5 +1,6 @@ use std::f32; +use crate::math::MintVec2; use crate::sys; use crate::window::WindowFlags; use crate::Ui; @@ -47,8 +48,8 @@ impl<'ui, Label: AsRef> ChildWindow<'ui, Label> { /// - `= 0.0`: use remaining host window size /// - `< 0.0`: use remaining host window size minus abs(size) #[inline] - pub fn size(mut self, size: [f32; 2]) -> Self { - self.size = size; + pub fn size(mut self, size: impl Into) -> Self { + self.size = size.into().into(); self } /// Sets the window content size, which can be used to enforce scrollbars. @@ -57,8 +58,8 @@ impl<'ui, Label: AsRef> ChildWindow<'ui, Label> { /// 0.0 to leave the size automatic. #[inline] #[doc(alias = "SetNextWindowContentSize")] - pub fn content_size(mut self, size: [f32; 2]) -> Self { - self.content_size = size; + pub fn content_size(mut self, size: impl Into) -> Self { + self.content_size = size.into().into(); self } /// Sets the window focused state, which can be used to bring the window to front diff --git a/imgui/src/window/mod.rs b/imgui/src/window/mod.rs index a0f873c..6183ca8 100644 --- a/imgui/src/window/mod.rs +++ b/imgui/src/window/mod.rs @@ -2,6 +2,7 @@ use bitflags::bitflags; use std::f32; use std::ptr; +use crate::math::MintVec2; use crate::sys; use crate::{Condition, Ui}; @@ -165,13 +166,13 @@ pub struct Window<'ui, 'a, Label> { name: Label, opened: Option<&'a mut bool>, flags: WindowFlags, - pos: [f32; 2], + pos: MintVec2, pos_cond: Condition, - pos_pivot: [f32; 2], - size: [f32; 2], + pos_pivot: MintVec2, + size: MintVec2, size_cond: Condition, - size_constraints: Option<([f32; 2], [f32; 2])>, - content_size: [f32; 2], + size_constraints: Option<(MintVec2, MintVec2)>, + content_size: MintVec2, collapsed: bool, collapsed_cond: Condition, focused: bool, @@ -186,13 +187,13 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { name, opened: None, flags: WindowFlags::empty(), - pos: [0.0, 0.0], + pos: [0.0, 0.0].into(), pos_cond: Condition::Never, - pos_pivot: [0.0, 0.0], - size: [0.0, 0.0], + pos_pivot: [0.0, 0.0].into(), + size: [0.0, 0.0].into(), size_cond: Condition::Never, size_constraints: None, - content_size: [0.0, 0.0], + content_size: [0.0, 0.0].into(), collapsed: false, collapsed_cond: Condition::Never, focused: false, @@ -213,8 +214,8 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { } /// Sets the window position, which is applied based on the given condition value #[inline] - pub fn position(mut self, position: [f32; 2], condition: Condition) -> Self { - self.pos = position; + pub fn position(mut self, position: impl Into, condition: Condition) -> Self { + self.pos = position.into(); self.pos_cond = condition; self } @@ -224,14 +225,14 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { /// For example, pass [0.5, 0.5] to center the window on the position. /// Does nothing if window position is not also set with `position()`. #[inline] - pub fn position_pivot(mut self, pivot: [f32; 2]) -> Self { - self.pos_pivot = pivot; + pub fn position_pivot(mut self, pivot: impl Into) -> Self { + self.pos_pivot = pivot.into(); self } /// Sets the window size, which is applied based on the given condition value #[inline] - pub fn size(mut self, size: [f32; 2], condition: Condition) -> Self { - self.size = size; + pub fn size(mut self, size: impl Into, condition: Condition) -> Self { + self.size = size.into(); self.size_cond = condition; self } @@ -239,8 +240,12 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { /// /// Use -1.0, -1.0 on either X or Y axis to preserve current size. #[inline] - pub fn size_constraints(mut self, size_min: [f32; 2], size_max: [f32; 2]) -> Self { - self.size_constraints = Some((size_min, size_max)); + pub fn size_constraints( + mut self, + size_min: impl Into, + size_max: impl Into, + ) -> Self { + self.size_constraints = Some((size_min.into(), size_max.into())); self } /// Sets the window content size, which can be used to enforce scrollbars. @@ -248,8 +253,8 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { /// Does not include window decorations (title bar, menu bar, etc.). Set one of the values to /// 0.0 to leave the size automatic. #[inline] - pub fn content_size(mut self, size: [f32; 2]) -> Self { - self.content_size = size; + pub fn content_size(mut self, size: impl Into) -> Self { + self.content_size = size.into(); self } /// Sets the window collapse state, which is applied based on the given condition value @@ -513,7 +518,7 @@ impl<'ui, 'a, Label: AsRef> Window<'ui, 'a, Label> { ) }; } - if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 { + if self.content_size.x != 0.0 || self.content_size.y != 0.0 { unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) }; } if self.collapsed_cond != Condition::Never {