Skip to content

Commit

Permalink
Merge pull request imgui-rs#440 from sanbox-irl/feat_permissive_dropping
Browse files Browse the repository at this point in the history
permissive dropping
  • Loading branch information
sanbox-irl authored Mar 1, 2021
2 parents 3d3097e + 6010a3d commit 75fdec0
Show file tree
Hide file tree
Showing 18 changed files with 500 additions and 546 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

- Removed legacy `ImGuiDragDropFlags` from `legacy.rs`, which were accidentally not cleared when they were remade in `drag_drop.rs` in v0.7.0.

- Most tokens through the repository (eg. `WindowToken`, `TabBarToken`, `FontStackToken`, etc) now allow for permissive dropping -- i.e, you don't need to actually call the `.end()` method on them anymore. In exchange, these tokens have taken on a lifetime, which allows them to be safe. This could make some patterns impossible. Please file an issue if this causes a problem.
- `end()` no longer takes `Ui`. This is a breaking change, but hopefully should be trivial (and perhaps nice) for users to fix. Simply delete the argument, or add a `_` before the token's binding name and allow it to be dropped on its own.

- `PopupModal`'s `new` was reworked so that it didn't take `Ui` until `build` was called. This is a breaking change if you were invoking it directly. Simply move your `ui` call to `build` or `begin`.

## [0.7.0] - 2021-02-04

- Upgrade to [Dear ImGui v1.80](https://github.com/ocornut/imgui/releases/tag/v1.80). (Note that the new table functionality is not yet supported, however)
Expand Down
4 changes: 2 additions & 2 deletions imgui-examples/examples/multiple_fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ fn main() {
ui.text("Hello, I'm Roboto Regular!");
let _dokdo = ui.push_font(dokdo);
ui.text("Hello, I'm Dokdo Regular!");
_dokdo.pop(&ui);
_dokdo.pop();
ui.text("Hello, I'm Roboto Regular again!");
_roboto.pop(&ui);
_roboto.pop();
ui.text("Hello, I'm the default font again!");
});
});
Expand Down
36 changes: 18 additions & 18 deletions imgui-examples/examples/test_window_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
if let Some(menu_bar) = ui.begin_menu_bar() {
if let Some(menu) = ui.begin_menu(im_str!("Menu"), true) {
show_example_menu_file(ui, &mut state.file_menu);
menu.end(ui);
menu.end();
}
if let Some(menu) = ui.begin_menu(im_str!("Examples"), true) {
MenuItem::new(im_str!("Main menu bar"))
Expand All @@ -363,7 +363,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
.build_with_ref(ui, &mut state.show_app_manipulating_window_title);
MenuItem::new(im_str!("Custom rendering"))
.build_with_ref(ui, &mut state.show_app_custom_rendering);
menu.end(ui);
menu.end();
}
if let Some(menu) = ui.begin_menu(im_str!("Help"), true) {
MenuItem::new(im_str!("Metrics"))
Expand All @@ -372,9 +372,9 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) {
.build_with_ref(ui, &mut state.show_app_style_editor);
MenuItem::new(im_str!("About ImGui"))
.build_with_ref(ui, &mut state.show_app_about);
menu.end(ui);
menu.end();
}
menu_bar.end(ui);
menu_bar.end();
}
ui.spacing();
if CollapsingHeader::new(im_str!("Help")).build(&ui) {
Expand Down Expand Up @@ -709,7 +709,7 @@ CTRL+click on individual component to input value.\n",
ui.checkbox(im_str!("Celery"), &mut s.celery_tab);
ui.same_line(0.0);
ui.checkbox(im_str!("Daikon"), &mut s.daikon_tab);
style.pop(ui);
style.pop();

let flags = {
let mut f = TabBarFlags::empty();
Expand Down Expand Up @@ -782,7 +782,7 @@ CTRL+click on individual component to input value.\n",
if ui.button(im_str!("Delete.."), [0.0, 0.0]) {
ui.open_popup(im_str!("Delete?"));
}
ui.popup_modal(im_str!("Delete?")).always_auto_resize(true).build(|| {
PopupModal::new(im_str!("Delete?")).always_auto_resize(true).build(ui, || {
ui.text("All those beautiful files will be deleted.\nThis operation cannot be undone!\n\n");
ui.separator();
let style = ui.push_style_var(StyleVar::FramePadding([0.0, 0.0]));
Expand All @@ -795,13 +795,13 @@ CTRL+click on individual component to input value.\n",
if ui.button(im_str!("Cancel"), [120.0, 0.0]) {
ui.close_current_popup();
}
style.pop(ui);
style.pop();
});

if ui.button(im_str!("Stacked modals.."), [0.0, 0.0]) {
ui.open_popup(im_str!("Stacked 1"));
}
ui.popup_modal(im_str!("Stacked 1")).build(|| {
PopupModal::new(im_str!("Stacked 1")).build(ui, || {
ui.text(
"Hello from Stacked The First\n\
Using style[StyleColor::ModalWindowDarkening] for darkening."
Expand All @@ -815,7 +815,7 @@ CTRL+click on individual component to input value.\n",
if ui.button(im_str!("Add another modal.."), [0.0, 0.0]) {
ui.open_popup(im_str!("Stacked 2")) ;
}
ui.popup_modal(im_str!("Stacked 2")).build(|| {
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]) {
ui.close_current_popup();
Expand All @@ -835,7 +835,7 @@ 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) {
show_example_menu_file(ui, &mut state.file_menu);
menu.end(ui);
menu.end();
}
if let Some(menu) = ui.begin_menu(im_str!("Edit"), true) {
MenuItem::new(im_str!("Undo"))
Expand All @@ -855,9 +855,9 @@ fn show_example_app_main_menu_bar<'a>(ui: &Ui<'a>, state: &mut State) {
MenuItem::new(im_str!("Paste"))
.shortcut(im_str!("CTRL+V"))
.build(ui);
menu.end(ui);
menu.end();
}
menu_bar.end(ui);
menu_bar.end();
}
}

Expand All @@ -878,11 +878,11 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
MenuItem::new(im_str!("Sailor")).build(ui);
if let Some(menu) = ui.begin_menu(im_str!("Recurse.."), true) {
show_example_menu_file(ui, state);
menu.end(ui);
menu.end();
}
menu.end(ui);
menu.end();
}
menu.end(ui);
menu.end();
}
MenuItem::new(im_str!("Save"))
.shortcut(im_str!("Ctrl+S"))
Expand All @@ -909,13 +909,13 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
let items = [im_str!("Yes"), im_str!("No"), im_str!("Maybe")];
ComboBox::new(im_str!("Combo")).build_simple_string(ui, &mut state.n, &items);
ui.checkbox(im_str!("Check"), &mut state.b);
menu.end(ui);
menu.end();
}
if let Some(menu) = ui.begin_menu(im_str!("Colors"), true) {
for &col in StyleColor::VARIANTS.iter() {
MenuItem::new(&im_str!("{:?}", col)).build(ui);
}
menu.end(ui);
menu.end();
}
assert!(ui.begin_menu(im_str!("Disabled"), false).is_none());
MenuItem::new(im_str!("Checked")).selected(true).build(ui);
Expand Down Expand Up @@ -966,7 +966,7 @@ fn show_example_app_fixed_overlay(ui: &Ui, opened: &mut bool) {
mouse_pos[0], mouse_pos[1]
));
});
style.pop(ui);
style.pop();
}

fn show_example_app_manipulating_window_title(ui: &Ui) {
Expand Down
35 changes: 9 additions & 26 deletions imgui/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
use std::ptr;
use std::thread;

use crate::context::Context;
use crate::sys;
use crate::Ui;

/// Tracks a layout group that must be ended by calling `.end()`
#[must_use]
pub struct GroupToken {
ctx: *const Context,
}
create_token!(
/// Tracks a layout group that can be ended with `end` or by dropping.
pub struct GroupToken<'ui>;

impl GroupToken {
/// Ends a layout group
pub fn end(mut self, _: &Ui) {
self.ctx = ptr::null();
unsafe { sys::igEndGroup() };
}
}

impl Drop for GroupToken {
fn drop(&mut self) {
if !self.ctx.is_null() && !thread::panicking() {
panic!("A GroupToken was leaked. Did you call .end()?");
}
}
}
/// Drops the layout group manually. You can also just allow this token
/// to drop on its own.
drop { sys::igEndGroup() }
);

/// # Cursor / Layout
impl<'ui> Ui<'ui> {
Expand Down Expand Up @@ -84,15 +67,15 @@ impl<'ui> Ui<'ui> {
/// Returns a `GroupToken` that must be ended by calling `.end()`
pub fn begin_group(&self) -> GroupToken {
unsafe { sys::igBeginGroup() };
GroupToken { ctx: self.ctx }
GroupToken::new(self)
}
/// Creates a layout group and runs a closure to construct the contents.
///
/// May be useful to handle the same mouse event on a group of items, for example.
pub fn group<R, F: FnOnce() -> R>(&self, f: F) -> R {
let group = self.begin_group();
let result = f();
group.end(self);
group.end();
result
}
/// Returns the cursor position (in window coordinates)
Expand Down
81 changes: 14 additions & 67 deletions imgui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub use self::legacy::*;
pub use self::list_clipper::ListClipper;
pub use self::plothistogram::PlotHistogram;
pub use self::plotlines::PlotLines;
pub use self::popup_modal::PopupModal;
pub use self::popups::*;
pub use self::render::draw_data::*;
pub use self::render::renderer::*;
pub use self::stacks::*;
Expand All @@ -54,6 +54,9 @@ use internal::RawCast;
#[macro_use]
mod string;

#[macro_use]
mod tokens;

mod clipboard;
pub mod color;
mod columns;
Expand All @@ -70,7 +73,7 @@ mod legacy;
mod list_clipper;
mod plothistogram;
mod plotlines;
mod popup_modal;
mod popups;
mod render;
mod stacks;
mod style;
Expand Down Expand Up @@ -287,27 +290,14 @@ impl<'ui> Ui<'ui> {
}
}

/// Tracks a layout tooltip that must be ended by calling `.end()`
#[must_use]
pub struct TooltipToken {
ctx: *const Context,
}

impl TooltipToken {
/// Ends a layout tooltip
pub fn end(mut self, _: &Ui) {
self.ctx = ptr::null();
unsafe { sys::igEndTooltip() };
}
}
create_token!(
/// Tracks a layout tooltip that can be ended by calling `.end()` or by dropping.
pub struct TooltipToken<'ui>;

impl Drop for TooltipToken {
fn drop(&mut self) {
if !self.ctx.is_null() && !thread::panicking() {
panic!("A TooltipToken was leaked. Did you call .end()?");
}
}
}
/// Drops the layout tooltip manually. You can also just allow this token
/// to drop on its own.
drop { sys::igEndTooltip() }
);

/// # Tooltips
impl<'ui> Ui<'ui> {
Expand Down Expand Up @@ -336,9 +326,9 @@ impl<'ui> Ui<'ui> {
/// Construct a tooltip window that can have any kind of content.
///
/// Returns a `TooltipToken` that must be ended by calling `.end()`
pub fn begin_tooltip(&self) -> TooltipToken {
pub fn begin_tooltip(&self) -> TooltipToken<'_> {
unsafe { sys::igBeginTooltip() };
TooltipToken { ctx: self.ctx }
TooltipToken::new(self)
}
/// Construct a tooltip window with simple text content.
///
Expand All @@ -360,49 +350,6 @@ impl<'ui> Ui<'ui> {
}
}

// Widgets: Popups
impl<'ui> Ui<'ui> {
pub fn open_popup(&self, str_id: &ImStr) {
unsafe { sys::igOpenPopup(str_id.as_ptr(), 0) };
}
pub fn popup<F>(&self, str_id: &ImStr, f: F)
where
F: FnOnce(),
{
let render =
unsafe { sys::igBeginPopup(str_id.as_ptr(), WindowFlags::empty().bits() as i32) };
if render {
f();
unsafe { sys::igEndPopup() };
}
}
/// Create a modal pop-up.
///
/// # Example
/// ```rust,no_run
/// # use imgui::*;
/// # let mut imgui = Context::create();
/// # let ui = imgui.frame();
/// if ui.button(im_str!("Show modal"), [0.0, 0.0]) {
/// ui.open_popup(im_str!("modal"));
/// }
/// ui.popup_modal(im_str!("modal")).build(|| {
/// ui.text("Content of my modal");
/// if ui.button(im_str!("OK"), [0.0, 0.0]) {
/// ui.close_current_popup();
/// }
/// });
/// ```
pub fn popup_modal<'p>(&self, str_id: &'p ImStr) -> PopupModal<'ui, 'p> {
PopupModal::new(self, str_id)
}
/// Close a popup. Should be called within the closure given as argument to
/// [`Ui::popup`] or [`Ui::popup_modal`].
pub fn close_current_popup(&self) {
unsafe { sys::igCloseCurrentPopup() };
}
}

// Widgets: ListBox
impl<'ui> Ui<'ui> {
pub fn list_box<'p, StringType: AsRef<ImStr> + ?Sized>(
Expand Down
6 changes: 5 additions & 1 deletion imgui/src/list_clipper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,11 @@ impl<'ui> Drop for ListClipperToken<'ui> {
sys::ImGuiListClipper_destroy(self.list_clipper);
};
} else if !thread::panicking() {
panic!("Forgot to call End(), or to Step() until false?");
panic!(
"Forgot to call End(), or to Step() until false? \
This is the only token in the repository which users must call `.end()` or `.step()` \
with. See https://github.com/imgui-rs/imgui-rs/issues/438"
);
}
}
}
Loading

0 comments on commit 75fdec0

Please sign in to comment.