Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat permissive dropping, in which i suffer #440

Merged
merged 7 commits into from Mar 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.markdown
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
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
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
@@ -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
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
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"
);
}
}
}