From 8c328001d05ce3a50287a78460d5abc84f7670cf Mon Sep 17 00:00:00 2001 From: Jonathan Spira Date: Sun, 28 Feb 2021 13:50:46 -0800 Subject: [PATCH] Added ext function variants to the majority of overloaded functions in ImGui --- imgui-examples/examples/draw_list.rs | 4 +- imgui-examples/examples/test_window_impl.rs | 86 +++++++++++---------- imgui/src/drag_drop.rs | 12 +-- imgui/src/input/keyboard.rs | 26 ++++++- imgui/src/input/mouse.rs | 41 ++++++---- imgui/src/layout.rs | 32 +++++++- imgui/src/lib.rs | 21 ++++- imgui/src/stacks.rs | 15 +++- imgui/src/utils.rs | 12 ++- imgui/src/widget/menu.rs | 31 +++++++- imgui/src/widget/misc.rs | 16 +++- imgui/src/window/scroll.rs | 20 +++-- 12 files changed, 231 insertions(+), 85 deletions(-) diff --git a/imgui-examples/examples/draw_list.rs b/imgui-examples/examples/draw_list.rs index a80aa48..716f959 100644 --- a/imgui-examples/examples/draw_list.rs +++ b/imgui-examples/examples/draw_list.rs @@ -10,7 +10,7 @@ fn draw_text_centered( text: &ImStr, color: [f32; 3], ) { - let text_size = ui.calc_text_size(text, false, 0.0); + let text_size = ui.calc_text_size(text); let cx = (rect[2] - text_size[0]) / 2.0; let cy = (rect[3] - text_size[1]) / 2.0; draw_list.add_text([rect[0] + cx, rect[1] + cy], color, text); @@ -54,7 +54,7 @@ fn main() { .size([300.0, 110.0], Condition::FirstUseEver) .scroll_bar(false) .build(ui, || { - ui.button(im_str!("random button"), [0.0, 0.0]); + ui.button(im_str!("random button")); let draw_list = ui.get_window_draw_list(); let o = ui.cursor_screen_pos(); let ws = ui.content_region_avail(); diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index 4240561..e5abed1 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -336,11 +336,11 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.push_item_width(-140.0); ui.text(format!("dear imgui says hello. ({})", imgui::dear_imgui_version())); if let Some(menu_bar) = ui.begin_menu_bar() { - if let Some(menu) = ui.begin_menu(im_str!("Menu"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Menu")) { show_example_menu_file(ui, &mut state.file_menu); menu.end(); } - if let Some(menu) = ui.begin_menu(im_str!("Examples"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Examples")) { MenuItem::new(im_str!("Main menu bar")) .build_with_ref(ui, &mut state.show_app_main_menu_bar); MenuItem::new(im_str!("Console")) @@ -365,7 +365,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { .build_with_ref(ui, &mut state.show_app_custom_rendering); menu.end(); } - if let Some(menu) = ui.begin_menu(im_str!("Help"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Help")) { MenuItem::new(im_str!("Metrics")) .build_with_ref(ui, &mut state.show_app_metrics); MenuItem::new(im_str!("Style Editor")) @@ -388,14 +388,14 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { if CollapsingHeader::new(im_str!("Window options")).build(&ui) { ui.checkbox(im_str!("No titlebar"), &mut state.no_titlebar); - ui.same_line(150.0); + ui.same_line_with_pos(150.0); ui.checkbox(im_str!("No scrollbar"), &mut state.no_scrollbar); - ui.same_line(300.0); + ui.same_line_with_pos(300.0); ui.checkbox(im_str!("No menu"), &mut state.no_menu); ui.checkbox(im_str!("No move"), &mut state.no_move); - ui.same_line(150.0); + ui.same_line_with_pos(150.0); ui.checkbox(im_str!("No resize"), &mut state.no_resize); - ui.same_line(300.0); + ui.same_line_with_pos(300.0); ui.checkbox(im_str!("No collapse"), &mut state.no_collapse); ui.checkbox(im_str!("No close"), &mut state.no_close); @@ -408,7 +408,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { for i in 0..5 { TreeNode::new(&im_str!("Child {}", i)).build(&ui, || { ui.text(im_str!("blah blah")); - ui.same_line(0.0); + ui.same_line(); if ui.small_button(im_str!("print")) { println!("Child {} pressed", i); } @@ -473,9 +473,9 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { }); ui.radio_button(im_str!("radio a"), &mut state.radio_button, 0); - ui.same_line(0.0); + ui.same_line(); ui.radio_button(im_str!("radio b"), &mut state.radio_button, 1); - ui.same_line(0.0); + ui.same_line(); ui.radio_button(im_str!("radio c"), &mut state.radio_button, 2); ui.separator(); @@ -568,7 +568,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { TreeNode::new(im_str!("Color/Picker Widgets")).build(&ui, || { let s = &mut state.color_edit; ui.checkbox(im_str!("With HDR"), &mut s.hdr); - ui.same_line(0.0); + ui.same_line(); show_help_marker( ui, "Currently all this does is to lift the 0..1 \ @@ -581,7 +581,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { &mut s.alpha_half_preview, ); ui.checkbox(im_str!("With Options Menu"), &mut s.options_menu); - ui.same_line(0.0); + ui.same_line(); show_help_marker( ui, "Right-click on the individual color widget to \ @@ -599,7 +599,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { }; ui.text(im_str!("Color widget:")); - ui.same_line(0.0); + ui.same_line(); show_help_marker( ui, "Click on the colored square to open a color picker. @@ -623,7 +623,7 @@ CTRL+click on individual component to input value.\n", .build(ui); ui.text(im_str!("Color button with Picker:")); - ui.same_line(0.0); + ui.same_line(); show_help_marker( ui, "With the inputs(false) function you can hide all \ @@ -642,10 +642,10 @@ CTRL+click on individual component to input value.\n", ui.checkbox(im_str!("With Alpha Bar"), &mut s.alpha_bar); ui.checkbox(im_str!("With Side Preview"), &mut s.side_preview); if s.side_preview { - ui.same_line(0.0); + ui.same_line(); ui.checkbox(im_str!("With Ref Color"), &mut s.ref_color); if s.ref_color { - ui.same_line(0.0); + ui.same_line(); ColorEdit::new(im_str!("##RefColor"), &mut s.ref_color_v) .flags(misc_flags) .inputs(false) @@ -703,11 +703,11 @@ CTRL+click on individual component to input value.\n", } let style = ui.push_style_var(StyleVar::FramePadding([0.0, 0.0])); ui.checkbox(im_str!("Artichoke"), &mut s.artichoke_tab); - ui.same_line(0.0); + ui.same_line(); ui.checkbox(im_str!("Beetroot"), &mut s.beetroot_tab); - ui.same_line(0.0); + ui.same_line(); ui.checkbox(im_str!("Celery"), &mut s.celery_tab); - ui.same_line(0.0); + ui.same_line(); ui.checkbox(im_str!("Daikon"), &mut s.daikon_tab); style.pop(); @@ -757,7 +757,7 @@ CTRL+click on individual component to input value.\n", if ui.small_button(im_str!("Select..")) { ui.open_popup(im_str!("select")); } - ui.same_line(0.0); + ui.same_line(); ui.text(match state.selected_fish { Some(index) => names[index], None => im_str!(""), @@ -779,7 +779,7 @@ CTRL+click on individual component to input value.\n", them by clicking outside the window." )); - if ui.button(im_str!("Delete.."), [0.0, 0.0]) { + if ui.button(im_str!("Delete..")) { ui.open_popup(im_str!("Delete?")); } PopupModal::new(im_str!("Delete?")).always_auto_resize(true).build(ui, || { @@ -788,17 +788,17 @@ CTRL+click on individual component to input value.\n", let style = ui.push_style_var(StyleVar::FramePadding([0.0, 0.0])); ui.checkbox(im_str!("Don't ask me next time"), &mut state.dont_ask_me_next_time); - if ui.button(im_str!("OK"), [120.0, 0.0]) { + if ui.button_with_size(im_str!("OK"), [120.0, 0.0]) { ui.close_current_popup(); } - ui.same_line(0.0); - if ui.button(im_str!("Cancel"), [120.0, 0.0]) { + ui.same_line(); + if ui.button_with_size(im_str!("Cancel"), [120.0, 0.0]) { ui.close_current_popup(); } style.pop(); }); - if ui.button(im_str!("Stacked modals.."), [0.0, 0.0]) { + if ui.button(im_str!("Stacked modals..")) { ui.open_popup(im_str!("Stacked 1")); } PopupModal::new(im_str!("Stacked 1")).build(ui, || { @@ -812,17 +812,17 @@ CTRL+click on individual component to input value.\n", ColorEdit::new(im_str!("color"), &mut state.stacked_modals_color).build(ui); - if ui.button(im_str!("Add another modal.."), [0.0, 0.0]) { + if ui.button(im_str!("Add another modal..")) { ui.open_popup(im_str!("Stacked 2")) ; } PopupModal::new(im_str!("Stacked 2")).build(ui, || { ui.text("Hello from Stacked The Second"); - if ui.button(im_str!("Close"), [0.0, 0.0]) { + if ui.button(im_str!("Close")) { ui.close_current_popup(); } }); - if ui.button(im_str!("Close"), [0.0, 0.0]) { + if ui.button(im_str!("Close")) { ui.close_current_popup(); } }); @@ -833,11 +833,11 @@ CTRL+click on individual component to input value.\n", fn show_example_app_main_menu_bar<'a>(ui: &Ui<'a>, state: &mut State) { if let Some(menu_bar) = ui.begin_main_menu_bar() { - if let Some(menu) = ui.begin_menu(im_str!("File"), true) { + if let Some(menu) = ui.begin_menu(im_str!("File")) { show_example_menu_file(ui, &mut state.file_menu); menu.end(); } - if let Some(menu) = ui.begin_menu(im_str!("Edit"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Edit")) { MenuItem::new(im_str!("Undo")) .shortcut(im_str!("CTRL+Z")) .build(ui); @@ -869,14 +869,14 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) { MenuItem::new(im_str!("Open")) .shortcut(im_str!("Ctrl+O")) .build(ui); - if let Some(menu) = ui.begin_menu(im_str!("Open Recent"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Open Recent")) { MenuItem::new(im_str!("fish_hat.c")).build(ui); MenuItem::new(im_str!("fish_hat.inl")).build(ui); MenuItem::new(im_str!("fish_hat.h")).build(ui); - if let Some(menu) = ui.begin_menu(im_str!("More.."), true) { + if let Some(menu) = ui.begin_menu(im_str!("More..")) { MenuItem::new(im_str!("Hello")).build(ui); MenuItem::new(im_str!("Sailor")).build(ui); - if let Some(menu) = ui.begin_menu(im_str!("Recurse.."), true) { + if let Some(menu) = ui.begin_menu(im_str!("Recurse..")) { show_example_menu_file(ui, state); menu.end(); } @@ -889,7 +889,7 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) { .build(ui); MenuItem::new(im_str!("Save As..")).build(ui); ui.separator(); - if let Some(menu) = ui.begin_menu(im_str!("Options"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Options")) { MenuItem::new(im_str!("Enabled")).build_with_ref(ui, &mut state.enabled); ChildWindow::new("child") .size([0.0, 60.0]) @@ -911,13 +911,15 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) { ui.checkbox(im_str!("Check"), &mut state.b); menu.end(); } - if let Some(menu) = ui.begin_menu(im_str!("Colors"), true) { + if let Some(menu) = ui.begin_menu(im_str!("Colors")) { for &col in StyleColor::VARIANTS.iter() { MenuItem::new(&im_str!("{:?}", col)).build(ui); } menu.end(); } - assert!(ui.begin_menu(im_str!("Disabled"), false).is_none()); + assert!(ui + .begin_menu_with_enabled(im_str!("Disabled"), false) + .is_none()); MenuItem::new(im_str!("Checked")).selected(true).build(ui); MenuItem::new(im_str!("Quit")) .shortcut(im_str!("Alt+F4")) @@ -1132,12 +1134,12 @@ fn show_example_app_custom_rendering(ui: &Ui, state: &mut CustomRenderingState, ui.separator(); ui.text(im_str!("Canvas example")); - if ui.button(im_str!("Clear"), [0.0, 0.0]) { + if ui.button(im_str!("Clear")) { state.points.clear(); } if state.points.len() >= 2 { - ui.same_line(0.0); - if ui.button(im_str!("Undo"), [0.0, 0.0]) { + ui.same_line(); + if ui.button(im_str!("Undo")) { state.points.pop(); state.points.pop(); } @@ -1272,11 +1274,11 @@ fn show_app_log(ui: &Ui, app_log: &mut Vec) { app_log.push(text); } } - if ui.button(im_str!("Clear"), [0.0, 0.0]) { + if ui.button(im_str!("Clear")) { app_log.clear(); } - ui.same_line(0.0); - if ui.button(im_str!("Copy"), [0.0, 0.0]) { + ui.same_line(); + if ui.button(im_str!("Copy")) { ui.set_clipboard_text(&ImString::from(app_log.join("\n"))); } ui.separator(); diff --git a/imgui/src/drag_drop.rs b/imgui/src/drag_drop.rs index 8c468d0..9b6d510 100644 --- a/imgui/src/drag_drop.rs +++ b/imgui/src/drag_drop.rs @@ -75,7 +75,7 @@ bitflags!( /// ```no_run /// # use imgui::*; /// fn show_ui(ui: &Ui<'_>) { -/// ui.button(im_str!("Hello, I am a drag source!"), [0.0, 0.0]); +/// ui.button(im_str!("Hello, I am a drag source!")); /// /// // Creates an empty DragSource with no tooltip /// DragDropSource::new(im_str!("BUTTON_DRAG")).begin(ui); @@ -143,7 +143,7 @@ impl<'a> DragDropSource<'a> { /// ```no_run /// # use imgui::*; /// fn show_ui(ui: &Ui<'_>, drop_message: &mut Option) { - /// ui.button(im_str!("Drag me!"), [0.0, 0.0]); + /// ui.button(im_str!("Drag me!")); /// /// let drag_drop_name = im_str!("Test Drag"); /// @@ -155,7 +155,7 @@ impl<'a> DragDropSource<'a> { /// *drop_message = Some("Test Payload".to_string()); /// } /// - /// ui.button(im_str!("Target me!"), [0.0, 0.0]); + /// ui.button(im_str!("Target me!")); /// /// // drag drop TARGET /// if let Some(target) = imgui::DragDropTarget::new(ui) { @@ -196,7 +196,7 @@ impl<'a> DragDropSource<'a> { /// ```no_run /// # use imgui::*; /// fn show_ui(ui: &Ui<'_>) { - /// ui.button(im_str!("Drag me!"), [0.0, 0.0]); + /// ui.button(im_str!("Drag me!")); /// /// let drag_drop_name = im_str!("Test Drag"); /// let msg_to_send = "hello there sailor"; @@ -207,7 +207,7 @@ impl<'a> DragDropSource<'a> { /// tooltip.end(); /// } /// - /// ui.button(im_str!("Target me!"), [0.0, 0.0]); + /// ui.button(im_str!("Target me!")); /// /// // drag drop TARGET /// if let Some(target) = imgui::DragDropTarget::new(ui) { @@ -313,7 +313,7 @@ impl Drop for DragDropSourceToolTip<'_> { /// # use imgui::*; /// fn show_ui(ui: &Ui<'_>) { /// // Drop something on this button please! -/// ui.button(im_str!("Hello, I am a drag Target!"), [0.0, 0.0]); +/// ui.button(im_str!("Hello, I am a drag Target!")); /// /// if let Some(target) = DragDropTarget::new(ui) { /// // accepting an empty payload (which is really just raising an event) diff --git a/imgui/src/input/keyboard.rs b/imgui/src/input/keyboard.rs index a2a586b..3124b60 100644 --- a/imgui/src/input/keyboard.rs +++ b/imgui/src/input/keyboard.rs @@ -107,6 +107,7 @@ impl<'ui> Ui<'ui> { let key_index = self.key_index(key); unsafe { sys::igIsKeyDown(key_index) } } + /// Returns true if the key was pressed (went from !down to down). /// /// Affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`) @@ -115,12 +116,23 @@ impl<'ui> Ui<'ui> { let key_index = self.key_index(key); unsafe { sys::igIsKeyPressed(key_index, true) } } + + /// Returns true if the key was pressed (went from !down to down). + /// + /// Is **not** affected by key repeat settings (`io.key_repeat_delay`, `io.key_repeat_rate`) + #[inline] + pub fn is_key_pressed_no_repeat(&self, key: Key) -> bool { + let key_index = self.key_index(key); + unsafe { sys::igIsKeyPressed(key_index, false) } + } + /// Returns true if the key was released (went from down to !down) #[inline] pub fn is_key_released(&self, key: Key) -> bool { let key_index = self.key_index(key); unsafe { sys::igIsKeyReleased(key_index) } } + /// Returns a count of key presses using the given repeat rate/delay settings. /// /// Usually returns 0 or 1, but might be >1 if `rate` is small enough that `io.delta_time` > @@ -130,9 +142,19 @@ impl<'ui> Ui<'ui> { let key_index = self.key_index(key); unsafe { sys::igGetKeyPressedAmount(key_index, repeat_delay, rate) as u32 } } - /// Focuses keyboard on a widget relative to current position + + /// Focuses keyboard on the next widget. + /// + /// This is the equivalent to [set_keyboard_focus_here_with_offset](Self::set_keyboard_focus_here_with_offset) + /// with `target_widget` set to `FocusedWidget::Next`. #[inline] - pub fn set_keyboard_focus_here(&self, target_widget: FocusedWidget) { + pub fn set_keyboard_focus_here(&self) { + self.set_keyboard_focus_here_with_offset(FocusedWidget::Next); + } + + /// Focuses keyboard on a widget relative to current position. + #[inline] + pub fn set_keyboard_focus_here_with_offset(&self, target_widget: FocusedWidget) { unsafe { sys::igSetKeyboardFocusHere(target_widget.as_offset()); } diff --git a/imgui/src/input/mouse.rs b/imgui/src/input/mouse.rs index 5d6e949..202f7c7 100644 --- a/imgui/src/input/mouse.rs +++ b/imgui/src/input/mouse.rs @@ -135,14 +135,27 @@ impl<'ui> Ui<'ui> { unsafe { sys::igGetMousePosOnOpeningCurrentPopup(&mut out) }; out.into() } - /// Returns the delta from the initial clicking position. + + /// Returns the delta from the initial position when the left mouse button clicked. /// /// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance /// threshold (`io.mouse_drag_threshold`). - pub fn mouse_drag_delta(&self, button: MouseButton) -> [f32; 2] { - let mut out = sys::ImVec2::zero(); - unsafe { sys::igGetMouseDragDelta(&mut out, button as i32, -1.0) }; - out.into() + /// + /// This is the same as [mouse_drag_delta_with_button](Self::mouse_drag_delta_with_button) with + /// `button` set to `MouseButton::Left`. + pub fn mouse_drag_delta(&self) -> [f32; 2] { + self.mouse_drag_delta_with_button(MouseButton::Left) + } + + /// Returns the delta from the initial position when the given button was clicked. + /// + /// This is locked and returns [0.0, 0.0] until the mouse has moved past the global distance + /// threshold (`io.mouse_drag_threshold`). + /// + /// This is the same as [mouse_drag_delta_with_threshold](Self::mouse_drag_delta_with_threshold) with + /// `threshold` set to `-1.0`, which uses the global threshold `io.mouse_drag_threshold`. + pub fn mouse_drag_delta_with_button(&self, button: MouseButton) -> [f32; 2] { + self.mouse_drag_delta_with_threshold(button, -1.0) } /// Returns the delta from the initial clicking position. /// @@ -353,7 +366,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 0.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] @@ -364,7 +377,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 0.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] @@ -375,7 +388,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 100.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 100.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] @@ -386,7 +399,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 200.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 200.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 200.0] @@ -398,7 +411,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [10.0, 10.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [10.0, 10.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [10.0, 10.0] @@ -409,7 +422,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(!ui.is_mouse_dragging(button)); assert!(!ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 0.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] @@ -420,7 +433,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [170.0, 170.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [170.0, 170.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [170.0, 170.0] @@ -428,7 +441,7 @@ fn test_mouse_drags() { ui.reset_mouse_drag_delta(button); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [0.0, 0.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [0.0, 0.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [0.0, 0.0] @@ -439,7 +452,7 @@ fn test_mouse_drags() { let ui = ctx.frame(); assert!(ui.is_mouse_dragging(button)); assert!(ui.is_mouse_dragging_with_threshold(button, 200.0)); - assert_eq!(ui.mouse_drag_delta(button), [20.0, 20.0]); + assert_eq!(ui.mouse_drag_delta_with_button(button), [20.0, 20.0]); assert_eq!( ui.mouse_drag_delta_with_threshold(button, 200.0), [20.0, 20.0] diff --git a/imgui/src/layout.rs b/imgui/src/layout.rs index 2997028..723ecb0 100644 --- a/imgui/src/layout.rs +++ b/imgui/src/layout.rs @@ -18,18 +18,34 @@ impl<'ui> Ui<'ui> { pub fn separator(&self) { unsafe { sys::igSeparator() } } + /// Call between widgets or groups to layout them horizontally. /// /// X position is given in window coordinates. - pub fn same_line(&self, pos_x: f32) { - unsafe { sys::igSameLine(pos_x, -1.0f32) } + /// + /// This is equivalent to calling [same_line_with_pos](Self::same_line_with_pos) + /// with the `pos` set to 0.0, which uses `Style::item_spacing`. + pub fn same_line(&self) { + self.same_line_with_pos(0.0); } + + /// Call between widgets or groups to layout them horizontally. + /// + /// X position is given in window coordinates. + /// + /// This is equivalent to calling [same_line_with_spacing](Self::same_line_with_spacing) + /// with the `spacing` set to -1.0, which means no extra spacing. + pub fn same_line_with_pos(&self, pos_x: f32) { + self.same_line_with_spacing(pos_x, -1.0) + } + /// Call between widgets or groups to layout them horizontally. /// /// X position is given in window coordinates. pub fn same_line_with_spacing(&self, pos_x: f32, spacing_w: f32) { unsafe { sys::igSameLine(pos_x, spacing_w) } } + /// Undo a `same_line` call or force a new line when in horizontal layout mode pub fn new_line(&self) { unsafe { sys::igNewLine() } @@ -44,17 +60,25 @@ impl<'ui> Ui<'ui> { pub fn dummy(&self, size: [f32; 2]) { unsafe { sys::igDummy(size.into()) } } + /// Moves content position to the right by `Style::indent_spacing` + /// + /// This is equivalent to [indent_by](Self::indent_by) with `width` set to + /// `Style::ident_spacing`. pub fn indent(&self) { - unsafe { sys::igIndent(0.0) }; + self.indent_by(0.0) } + /// Moves content position to the right by `width` pub fn indent_by(&self, width: f32) { unsafe { sys::igIndent(width) }; } /// Moves content position to the left by `Style::indent_spacing` + /// + /// This is equivalent to [unindent_by](Self::unindent_by) with `width` set to + /// `Style::ident_spacing`. pub fn unindent(&self) { - unsafe { sys::igUnindent(0.0) }; + self.unindent_by(0.0) } /// Moves content position to the left by `width` pub fn unindent_by(&self, width: f32) { diff --git a/imgui/src/lib.rs b/imgui/src/lib.rs index b104421..9633610 100644 --- a/imgui/src/lib.rs +++ b/imgui/src/lib.rs @@ -390,24 +390,37 @@ impl<'ui> Ui<'ui> { } impl<'ui> Ui<'ui> { + /// Calculate the size required for a given text string. + /// + /// This is the same as [calc_text_size_with_opts](Self::calc_text_size_with_opts) + /// with `hide_text_after_double_hash` set to false and `wrap_width` set to `-1.0`. + pub fn calc_text_size>(&self, text: T) -> [f32; 2] { + self.calc_text_size_with_opts(text, false, -1.0) + } + /// Calculate the size required for a given text string. /// /// hide_text_after_double_hash allows the user to insert comments into their text, using a double hash-tag prefix. /// This is a feature of imgui. /// /// wrap_width allows you to request a width at which to wrap the text to a newline for the calculation. - pub fn calc_text_size( + pub fn calc_text_size_with_opts>( &self, - text: &ImStr, + text: T, hide_text_after_double_hash: bool, wrap_width: f32, ) -> [f32; 2] { let mut out = sys::ImVec2::zero(); + let text = text.as_ref(); + unsafe { + let start = text.as_ptr(); + let end = start.add(text.len()); + sys::igCalcTextSize( &mut out, - text.as_ptr(), - std::ptr::null(), + start as *const c_char, + end as *const c_char, hide_text_after_double_hash, wrap_width, ) diff --git a/imgui/src/stacks.rs b/imgui/src/stacks.rs index 39381bd..7ad9b72 100644 --- a/imgui/src/stacks.rs +++ b/imgui/src/stacks.rs @@ -313,6 +313,18 @@ impl<'ui> Ui<'ui> { pub fn calc_item_width(&self) -> f32 { unsafe { sys::igCalcItemWidth() } } + + /// Changes the text wrapping position to the end of window (or column), which + /// is generally the default. + /// + /// This is the same as calling [push_text_wrap_pos_with_pos](Self::push_text_wrap_pos_with_pos) + /// with `wrap_pos_x` set to 0.0. + /// + /// Returns a `TextWrapPosStackToken` that may be popped by calling `.pop()` + pub fn push_text_wrap_pos(&self) -> TextWrapPosStackToken { + self.push_text_wrap_pos_with_pos(0.0) + } + /// Changes the text wrapping position by pushing a change to the text wrapping position stack. /// /// Returns a `TextWrapPosStackToken` that may be popped by calling `.pop()` @@ -320,10 +332,11 @@ impl<'ui> Ui<'ui> { /// - `> 0.0`: wrap at `wrap_pos_x` position in window local space /// - `= 0.0`: wrap to end of window (or column) /// - `< 0.0`: no wrapping - pub fn push_text_wrap_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken { + pub fn push_text_wrap_pos_with_pos(&self, wrap_pos_x: f32) -> TextWrapPosStackToken { unsafe { sys::igPushTextWrapPos(wrap_pos_x) }; TextWrapPosStackToken { _ctx: self.ctx } } + /// Changes an item flag by pushing a change to the item flag stack. /// /// Returns a `ItemFlagsStackToken` that may be popped by calling `.pop()` diff --git a/imgui/src/utils.rs b/imgui/src/utils.rs index aec0008..295948e 100644 --- a/imgui/src/utils.rs +++ b/imgui/src/utils.rs @@ -40,10 +40,20 @@ impl<'ui> Ui<'ui> { pub fn is_item_focused(&self) -> bool { unsafe { sys::igIsItemFocused() } } + + /// Returns `true` if the last item is being clicked by `MouseButton::Left`. + /// + /// This is the same as [is_item_clicked_with_button](Self::is_item_clicked_with_button) + /// with `button` set to `MouseButton::Left`. + pub fn is_item_clicked(&self) -> bool { + self.is_item_clicked_with_button(MouseButton::Left) + } + /// Returns `true` if the last item is being clicked - pub fn is_item_clicked(&self, button: MouseButton) -> bool { + pub fn is_item_clicked_with_button(&self, button: MouseButton) -> bool { unsafe { sys::igIsItemClicked(button as i32) } } + /// Returns `true` if the last item is visible pub fn is_item_visible(&self) -> bool { unsafe { sys::igIsItemVisible() } diff --git a/imgui/src/widget/menu.rs b/imgui/src/widget/menu.rs index c158327..585eb7a 100644 --- a/imgui/src/widget/menu.rs +++ b/imgui/src/widget/menu.rs @@ -50,6 +50,21 @@ impl<'ui> Ui<'ui> { f(); } } + + /// Creates and starts appending to a sub-menu entry. + /// + /// Returns `Some(MenuToken)` if the menu is visible. After content has been + /// rendered, the token must be ended by calling `.end()`. + /// + /// Returns `None` if the menu is not visible and no content should be rendered. + /// + /// This is the equivalent of [begin_menu_with_enabled](Self::begin_menu_with_enabled) + /// with `enabled` set to `true`. + #[must_use] + pub fn begin_menu(&self, label: &ImStr) -> Option> { + self.begin_menu_with_enabled(label, true) + } + /// Creates and starts appending to a sub-menu entry. /// /// Returns `Some(MenuToken)` if the menu is visible. After content has been @@ -57,7 +72,7 @@ impl<'ui> Ui<'ui> { /// /// Returns `None` if the menu is not visible and no content should be rendered. #[must_use] - pub fn begin_menu(&self, label: &ImStr, enabled: bool) -> Option> { + pub fn begin_menu_with_enabled(&self, label: &ImStr, enabled: bool) -> Option> { if unsafe { sys::igBeginMenu(label.as_ptr(), enabled) } { Some(MenuToken::new(self)) } else { @@ -67,8 +82,18 @@ impl<'ui> Ui<'ui> { /// Creates a menu and runs a closure to construct the contents. /// /// Note: the closure is not called if the menu is not visible. - pub fn menu(&self, label: &ImStr, enabled: bool, f: F) { - if let Some(_menu) = self.begin_menu(label, enabled) { + /// + /// This is the equivalent of [menu_with_enabled](Self::menu_with_enabled) + /// with `enabled` set to `true`. + pub fn menu(&self, label: &ImStr, f: F) { + self.menu_with_enabled(label, true, f); + } + + /// Creates a menu and runs a closure to construct the contents. + /// + /// Note: the closure is not called if the menu is not visible. + pub fn menu_with_enabled(&self, label: &ImStr, enabled: bool, f: F) { + if let Some(_menu) = self.begin_menu_with_enabled(label, enabled) { f(); } } diff --git a/imgui/src/widget/misc.rs b/imgui/src/widget/misc.rs index 9e51382..c5c4af3 100644 --- a/imgui/src/widget/misc.rs +++ b/imgui/src/widget/misc.rs @@ -23,7 +23,21 @@ impl<'ui> Ui<'ui> { /// Renders a clickable button. /// /// Returns true if this button was clicked. - pub fn button(&self, label: &ImStr, size: [f32; 2]) -> bool { + /// + /// This is the equivalent of [button_with_size](Self::button_with_size) + /// with `size` set to `[0.0, 0.0]`, which will size the button to the + /// label's width in the current style. + pub fn button(&self, label: &ImStr) -> bool { + self.button_with_size(label, [0.0, 0.0]) + } + + /// Renders a clickable button. + /// + /// Returns true if this button was clicked. + /// + /// Setting `size` as `[0.0, 0.0]` will size the button to the label's width in + /// the current style. + pub fn button_with_size(&self, label: &ImStr, size: [f32; 2]) -> bool { unsafe { sys::igButton(label.as_ptr(), size.into()) } } /// Renders a small clickable button that is easy to embed in text. diff --git a/imgui/src/window/scroll.rs b/imgui/src/window/scroll.rs index 5f271e9..ca6b3ca 100644 --- a/imgui/src/window/scroll.rs +++ b/imgui/src/window/scroll.rs @@ -35,9 +35,11 @@ impl<'ui> Ui<'ui> { pub fn set_scroll_y(&self, scroll_y: f32) { unsafe { sys::igSetScrollY(scroll_y) }; } - /// Adjusts the horizontal scroll position to make the current cursor position visible + /// Adjusts the horizontal scroll position to make the current cursor position visible. + /// + /// This is the same as [set_scroll_here_x_with_ratio](Self::set_scroll_here_x_with_ratio) but with `ratio` at 0.5. pub fn set_scroll_here_x(&self) { - unsafe { sys::igSetScrollHereX(0.5) }; + self.set_scroll_here_x_with_ratio(0.5); } /// Adjusts the horizontal scroll position to make the current cursor position visible. /// @@ -50,8 +52,10 @@ impl<'ui> Ui<'ui> { unsafe { sys::igSetScrollHereX(center_x_ratio) }; } /// Adjusts the vertical scroll position to make the current cursor position visible + /// + /// This is the same as [set_scroll_here_y_with_ratio](Self::set_scroll_here_y_with_ratio) but with `ratio` at 0.5. pub fn set_scroll_here_y(&self) { - unsafe { sys::igSetScrollHereY(0.5) }; + self.set_scroll_here_y_with_ratio(0.5); } /// Adjusts the vertical scroll position to make the current cursor position visible. /// @@ -64,8 +68,11 @@ impl<'ui> Ui<'ui> { unsafe { sys::igSetScrollHereY(center_y_ratio) }; } /// Adjusts the horizontal scroll position to make the given position visible + /// + /// This is the same as [set_scroll_from_pos_x_with_ratio](Self::set_scroll_from_pos_x_with_ratio) + /// but with `ratio` at 0.5. pub fn set_scroll_from_pos_x(&self, local_x: f32) { - unsafe { sys::igSetScrollFromPosX(local_x, 0.5) }; + self.set_scroll_from_pos_x_with_ratio(local_x, 0.5); } /// Adjusts the horizontal scroll position to make the given position visible. /// @@ -78,8 +85,11 @@ impl<'ui> Ui<'ui> { unsafe { sys::igSetScrollFromPosX(local_x, center_x_ratio) }; } /// Adjusts the vertical scroll position to make the given position visible + /// + /// This is the same as [set_scroll_from_pos_y_with_ratio](Self::set_scroll_from_pos_y_with_ratio) + /// but with `ratio` at 0.5. pub fn set_scroll_from_pos_y(&self, local_y: f32) { - unsafe { sys::igSetScrollFromPosY(local_y, 0.5) }; + self.set_scroll_from_pos_y_with_ratio(local_y, 0.5); } /// Adjusts the vertical scroll position to make the given position visible. ///