mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-12 05:58:35 +00:00
Merge pull request #440 from sanbox-irl/feat_permissive_dropping
permissive dropping
This commit is contained in:
commit
75fdec09d0
@ -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)
|
||||
|
||||
@ -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!");
|
||||
});
|
||||
});
|
||||
|
||||
@ -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"))
|
||||
@ -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"))
|
||||
@ -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) {
|
||||
@ -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();
|
||||
@ -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]));
|
||||
@ -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."
|
||||
@ -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();
|
||||
@ -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"))
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"))
|
||||
@ -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);
|
||||
@ -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) {
|
||||
|
||||
@ -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> {
|
||||
@ -84,7 +67,7 @@ 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.
|
||||
///
|
||||
@ -92,7 +75,7 @@ impl<'ui> Ui<'ui> {
|
||||
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)
|
||||
|
||||
@ -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::*;
|
||||
@ -54,6 +54,9 @@ use internal::RawCast;
|
||||
#[macro_use]
|
||||
mod string;
|
||||
|
||||
#[macro_use]
|
||||
mod tokens;
|
||||
|
||||
mod clipboard;
|
||||
pub mod color;
|
||||
mod columns;
|
||||
@ -70,7 +73,7 @@ mod legacy;
|
||||
mod list_clipper;
|
||||
mod plothistogram;
|
||||
mod plotlines;
|
||||
mod popup_modal;
|
||||
mod popups;
|
||||
mod render;
|
||||
mod stacks;
|
||||
mod style;
|
||||
@ -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,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a layout tooltip that can be ended by calling `.end()` or by dropping.
|
||||
pub struct TooltipToken<'ui>;
|
||||
|
||||
impl TooltipToken {
|
||||
/// Ends a layout tooltip
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndTooltip() };
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
@ -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.
|
||||
///
|
||||
@ -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>(
|
||||
|
||||
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,120 +0,0 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
|
||||
use crate::sys;
|
||||
use crate::window::WindowFlags;
|
||||
use crate::{ImStr, Ui};
|
||||
|
||||
/// Created by call to [`Ui::popup_modal`].
|
||||
#[must_use]
|
||||
pub struct PopupModal<'ui, 'p> {
|
||||
label: &'p ImStr,
|
||||
opened: Option<&'p mut bool>,
|
||||
flags: WindowFlags,
|
||||
_phantom: PhantomData<&'ui Ui<'ui>>,
|
||||
}
|
||||
|
||||
impl<'ui, 'p> PopupModal<'ui, 'p> {
|
||||
pub fn new(_: &Ui<'ui>, label: &'p ImStr) -> Self {
|
||||
PopupModal {
|
||||
label,
|
||||
opened: None,
|
||||
flags: WindowFlags::empty(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
/// Pass a mutable boolean which will be updated to refer to the current
|
||||
/// "open" state of the modal.
|
||||
pub fn opened(mut self, opened: &'p mut bool) -> Self {
|
||||
self.opened = Some(opened);
|
||||
self
|
||||
}
|
||||
pub fn flags(mut self, flags: WindowFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
pub fn title_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_TITLE_BAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn resizable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_RESIZE, !value);
|
||||
self
|
||||
}
|
||||
pub fn movable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_MOVE, !value);
|
||||
self
|
||||
}
|
||||
pub fn scroll_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn scrollable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn collapsible(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_COLLAPSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn always_auto_resize(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
|
||||
self
|
||||
}
|
||||
pub fn save_settings(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value);
|
||||
self
|
||||
}
|
||||
pub fn inputs(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_INPUTS, !value);
|
||||
self
|
||||
}
|
||||
pub fn menu_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::MENU_BAR, value);
|
||||
self
|
||||
}
|
||||
pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn no_focus_on_appearing(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, value);
|
||||
self
|
||||
}
|
||||
pub fn no_bring_to_front_on_focus(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, value);
|
||||
self
|
||||
}
|
||||
pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_use_window_padding(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
|
||||
self
|
||||
}
|
||||
/// Consume and draw the PopupModal.
|
||||
pub fn build<F: FnOnce()>(self, f: F) {
|
||||
let render = unsafe {
|
||||
sys::igBeginPopupModal(
|
||||
self.label.as_ptr(),
|
||||
self.opened
|
||||
.map(|x| x as *mut bool)
|
||||
.unwrap_or(ptr::null_mut()),
|
||||
self.flags.bits() as i32,
|
||||
)
|
||||
};
|
||||
if render {
|
||||
f();
|
||||
unsafe { sys::igEndPopup() };
|
||||
}
|
||||
}
|
||||
}
|
||||
212
imgui/src/popups.rs
Normal file
212
imgui/src/popups.rs
Normal file
@ -0,0 +1,212 @@
|
||||
use std::ptr;
|
||||
|
||||
use crate::sys;
|
||||
use crate::window::WindowFlags;
|
||||
use crate::{ImStr, Ui};
|
||||
|
||||
create_token!(
|
||||
/// Tracks a popup token that can be ended with `end` or by dropping.
|
||||
pub struct PopupToken<'ui>;
|
||||
|
||||
/// Drops the popup token manually. You can also just allow this token
|
||||
/// to drop on its own.
|
||||
drop { 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"));
|
||||
/// }
|
||||
/// if let Some(_token) = PopupModal::new(im_str!("modal")).begin_popup() {
|
||||
/// ui.text("Content of my modal");
|
||||
/// if ui.button(im_str!("OK"), [0.0, 0.0]) {
|
||||
/// ui.close_current_popup();
|
||||
/// }
|
||||
/// });
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub struct PopupModal<'p> {
|
||||
label: &'p ImStr,
|
||||
opened: Option<&'p mut bool>,
|
||||
flags: WindowFlags,
|
||||
}
|
||||
|
||||
impl<'p> PopupModal<'p> {
|
||||
pub fn new(label: &'p ImStr) -> Self {
|
||||
PopupModal {
|
||||
label,
|
||||
opened: None,
|
||||
flags: WindowFlags::empty(),
|
||||
}
|
||||
}
|
||||
/// Pass a mutable boolean which will be updated to refer to the current
|
||||
/// "open" state of the modal.
|
||||
pub fn opened(mut self, opened: &'p mut bool) -> Self {
|
||||
self.opened = Some(opened);
|
||||
self
|
||||
}
|
||||
pub fn flags(mut self, flags: WindowFlags) -> Self {
|
||||
self.flags = flags;
|
||||
self
|
||||
}
|
||||
pub fn title_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_TITLE_BAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn resizable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_RESIZE, !value);
|
||||
self
|
||||
}
|
||||
pub fn movable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_MOVE, !value);
|
||||
self
|
||||
}
|
||||
pub fn scroll_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
|
||||
self
|
||||
}
|
||||
pub fn scrollable(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn collapsible(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_COLLAPSE, !value);
|
||||
self
|
||||
}
|
||||
pub fn always_auto_resize(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
|
||||
self
|
||||
}
|
||||
pub fn save_settings(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_SAVED_SETTINGS, !value);
|
||||
self
|
||||
}
|
||||
pub fn inputs(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_INPUTS, !value);
|
||||
self
|
||||
}
|
||||
pub fn menu_bar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::MENU_BAR, value);
|
||||
self
|
||||
}
|
||||
pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn no_focus_on_appearing(mut self, value: bool) -> Self {
|
||||
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, value);
|
||||
self
|
||||
}
|
||||
pub fn no_bring_to_front_on_focus(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, value);
|
||||
self
|
||||
}
|
||||
pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
|
||||
self
|
||||
}
|
||||
pub fn always_use_window_padding(mut self, value: bool) -> Self {
|
||||
self.flags
|
||||
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Consume and draw the PopupModal.
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui<'_>, f: F) {
|
||||
if let Some(_popup) = self.begin_popup(ui) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume and draw the PopupModal.
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||
/// when you want to actual create the popup.
|
||||
pub fn begin_popup<'ui>(self, ui: &Ui<'ui>) -> Option<PopupToken<'ui>> {
|
||||
let render = unsafe {
|
||||
sys::igBeginPopupModal(
|
||||
self.label.as_ptr(),
|
||||
self.opened
|
||||
.map(|x| x as *mut bool)
|
||||
.unwrap_or(ptr::null_mut()),
|
||||
self.flags.bits() as i32,
|
||||
)
|
||||
};
|
||||
|
||||
if render {
|
||||
Some(PopupToken::new(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Widgets: Popups
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Instructs ImGui to open a popup, which must be began with either [`begin_popup`](Self::begin_popup)
|
||||
/// or [`popup`](Self::popup). You also use this function to begin [ModalPopups].
|
||||
///
|
||||
/// The confusing aspect to popups is that ImGui holds "control" over the popup fundamentally, so that ImGui
|
||||
/// can also force close a popup when a user clicks outside a popup. If you do not want users to be
|
||||
/// able to close a popup without selected an option, use [`PopupModal`].
|
||||
pub fn open_popup(&self, str_id: &ImStr) {
|
||||
unsafe { sys::igOpenPopup(str_id.as_ptr(), 0) };
|
||||
}
|
||||
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||
/// when you want to actual create the popup.
|
||||
pub fn begin_popup(&self, str_id: &ImStr) -> Option<PopupToken<'_>> {
|
||||
let render =
|
||||
unsafe { sys::igBeginPopup(str_id.as_ptr(), WindowFlags::empty().bits() as i32) };
|
||||
|
||||
if render {
|
||||
Some(PopupToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a popup that can have any kind of content.
|
||||
///
|
||||
/// This should be called *per frame*, whereas [`open_popup`](Self::open_popup) should be called *once*
|
||||
/// when you want to actual create the popup.
|
||||
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() };
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a PopupModal directly.
|
||||
#[deprecated = "Please use PopupModal to create a modal popup."]
|
||||
pub fn popup_modal<'p>(&self, str_id: &'p ImStr) -> PopupModal<'p> {
|
||||
PopupModal::new(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() };
|
||||
}
|
||||
}
|
||||
@ -34,13 +34,13 @@ impl<'ui> Ui<'ui> {
|
||||
/// ui.text("I use the custom font!");
|
||||
/// font.pop(&ui);
|
||||
/// ```
|
||||
pub fn push_font(&self, id: FontId) -> FontStackToken {
|
||||
pub fn push_font(&self, id: FontId) -> FontStackToken<'_> {
|
||||
let fonts = self.fonts();
|
||||
let font = fonts
|
||||
.get_font(id)
|
||||
.expect("Font atlas did not contain the given font");
|
||||
unsafe { sys::igPushFont(font.raw() as *const _ as *mut _) };
|
||||
FontStackToken { ctx: self.ctx }
|
||||
FontStackToken::new(self)
|
||||
}
|
||||
/// Changes a style color by pushing a change to the color stack.
|
||||
///
|
||||
@ -59,11 +59,9 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```
|
||||
pub fn push_style_color(&self, style_color: StyleColor, color: [f32; 4]) -> ColorStackToken {
|
||||
unsafe { sys::igPushStyleColorVec4(style_color as i32, color.into()) };
|
||||
ColorStackToken {
|
||||
count: 1,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
ColorStackToken::new(self)
|
||||
}
|
||||
|
||||
/// Changes style colors by pushing several changes to the color stack.
|
||||
///
|
||||
/// Returns a `ColorStackToken` that must be popped by calling `.pop()`
|
||||
@ -84,7 +82,8 @@ impl<'ui> Ui<'ui> {
|
||||
/// ui.text_disabled("I'm green!");
|
||||
/// colors.pop(&ui);
|
||||
/// ```
|
||||
pub fn push_style_colors<'a, I>(&self, style_colors: I) -> ColorStackToken
|
||||
#[deprecated = "deprecated in 0.7.0. Use `push_style_color` multiple times for similar effect."]
|
||||
pub fn push_style_colors<'a, I>(&self, style_colors: I) -> MultiColorStackToken
|
||||
where
|
||||
I: IntoIterator<Item = &'a (StyleColor, [f32; 4])>,
|
||||
{
|
||||
@ -93,14 +92,15 @@ impl<'ui> Ui<'ui> {
|
||||
unsafe { sys::igPushStyleColorVec4(style_color as i32, color.into()) };
|
||||
count += 1;
|
||||
}
|
||||
ColorStackToken {
|
||||
MultiColorStackToken {
|
||||
count,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
}
|
||||
/// Changes a style variable by pushing a change to the style stack.
|
||||
///
|
||||
/// Returns a `StyleStackToken` that must be popped by calling `.pop()`
|
||||
/// Returns a `StyleStackToken` that can be popped by calling `.end()`
|
||||
/// or by allowing to drop.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -114,10 +114,7 @@ impl<'ui> Ui<'ui> {
|
||||
/// ```
|
||||
pub fn push_style_var(&self, style_var: StyleVar) -> StyleStackToken {
|
||||
unsafe { push_style_var(style_var) };
|
||||
StyleStackToken {
|
||||
count: 1,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
StyleStackToken::new(self)
|
||||
}
|
||||
/// Changes style variables by pushing several changes to the style stack.
|
||||
///
|
||||
@ -137,7 +134,8 @@ impl<'ui> Ui<'ui> {
|
||||
/// ui.text("...with large spacing as well");
|
||||
/// styles.pop(&ui);
|
||||
/// ```
|
||||
pub fn push_style_vars<'a, I>(&self, style_vars: I) -> StyleStackToken
|
||||
#[deprecated = "deprecated in 0.7.0. Use `push_style_var` multiple times for similar effect."]
|
||||
pub fn push_style_vars<'a, I>(&self, style_vars: I) -> MultiStyleStackToken
|
||||
where
|
||||
I: IntoIterator<Item = &'a StyleVar>,
|
||||
{
|
||||
@ -146,43 +144,53 @@ impl<'ui> Ui<'ui> {
|
||||
unsafe { push_style_var(style_var) };
|
||||
count += 1;
|
||||
}
|
||||
StyleStackToken {
|
||||
MultiStyleStackToken {
|
||||
count,
|
||||
ctx: self.ctx,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a font pushed to the font stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct FontStackToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a font pushed to the font stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct FontStackToken<'ui>;
|
||||
|
||||
impl FontStackToken {
|
||||
/// Pops a change from the font stack
|
||||
pub fn pop(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igPopFont() };
|
||||
/// Pops a change from the font stack.
|
||||
drop { sys::igPopFont() }
|
||||
);
|
||||
|
||||
impl FontStackToken<'_> {
|
||||
/// Pops a change from the font stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FontStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A FontStackToken was leaked. Did you call .pop()?");
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a color pushed to the color stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct ColorStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the color stack.
|
||||
drop { sys::igPopStyleColor(1) }
|
||||
);
|
||||
|
||||
impl ColorStackToken<'_> {
|
||||
/// Pops a change from the color stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks one or more changes pushed to the color stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct ColorStackToken {
|
||||
pub struct MultiColorStackToken {
|
||||
count: usize,
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl ColorStackToken {
|
||||
impl MultiColorStackToken {
|
||||
/// Pops changes from the color stack
|
||||
pub fn pop(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
@ -190,7 +198,7 @@ impl ColorStackToken {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ColorStackToken {
|
||||
impl Drop for MultiColorStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A ColorStackToken was leaked. Did you call .pop()?");
|
||||
@ -198,14 +206,30 @@ impl Drop for ColorStackToken {
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks a style pushed to the style stack that can be popped by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct StyleStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the style stack.
|
||||
drop { sys::igPopStyleVar(1) }
|
||||
);
|
||||
|
||||
impl StyleStackToken<'_> {
|
||||
/// Pops a change from the style stack.
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks one or more changes pushed to the style stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct StyleStackToken {
|
||||
pub struct MultiStyleStackToken {
|
||||
count: usize,
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl StyleStackToken {
|
||||
impl MultiStyleStackToken {
|
||||
/// Pops changes from the style stack
|
||||
pub fn pop(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
@ -213,7 +237,7 @@ impl StyleStackToken {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for StyleStackToken {
|
||||
impl Drop for MultiStyleStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A StyleStackToken was leaked. Did you call .pop()?");
|
||||
@ -323,7 +347,6 @@ pub enum ItemFlag {
|
||||
ButtonRepeat(bool),
|
||||
}
|
||||
|
||||
/// Tracks a change pushed to the item width stack
|
||||
pub struct ItemWidthStackToken {
|
||||
_ctx: *const Context,
|
||||
}
|
||||
@ -372,13 +395,29 @@ impl ItemFlagsStackToken {
|
||||
}
|
||||
}
|
||||
|
||||
create_token!(
|
||||
/// Tracks an ID pushed to the ID stack that can be popped by calling `.pop()`
|
||||
/// or by dropping.
|
||||
pub struct IdStackToken<'ui>;
|
||||
|
||||
/// Pops a change from the ID stack
|
||||
drop { sys::igPopID() }
|
||||
);
|
||||
|
||||
impl IdStackToken<'_> {
|
||||
/// Pops a change from the ID stack
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
/// # ID stack
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Pushes an identifier to the ID stack.
|
||||
///
|
||||
/// Returns an `IdStackToken` that must be popped by calling `.pop()`
|
||||
///
|
||||
pub fn push_id<'a, I: Into<Id<'a>>>(&self, id: I) -> IdStackToken {
|
||||
/// Returns an `IdStackToken` that can be popped by calling `.end()`
|
||||
/// or by dropping manually.
|
||||
pub fn push_id<'a, I: Into<Id<'a>>>(&self, id: I) -> IdStackToken<'ui> {
|
||||
let id = id.into();
|
||||
|
||||
unsafe {
|
||||
@ -392,28 +431,6 @@ impl<'ui> Ui<'ui> {
|
||||
Id::Ptr(p) => sys::igPushIDPtr(p as *const c_void),
|
||||
}
|
||||
}
|
||||
IdStackToken { ctx: self.ctx }
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks an ID pushed to the ID stack that must be popped by calling `.pop()`
|
||||
#[must_use]
|
||||
pub struct IdStackToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl IdStackToken {
|
||||
/// Pops a change from the ID stack
|
||||
pub fn pop(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igPopID() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for IdStackToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A IdStackToken was leaked. Did you call .pop()?");
|
||||
}
|
||||
IdStackToken::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
43
imgui/src/tokens.rs
Normal file
43
imgui/src/tokens.rs
Normal file
@ -0,0 +1,43 @@
|
||||
#[macro_export]
|
||||
/// This is a macro used internally by imgui-rs to create StackTokens
|
||||
/// representing various global state in DearImGui.
|
||||
///
|
||||
/// These tokens can either be allowed to drop or dropped manually
|
||||
/// by called `end` on them. Preventing this token from dropping,
|
||||
/// or moving this token out of the block it was made in can have
|
||||
/// unintended side effects, including failed asserts in the DearImGui C++.
|
||||
///
|
||||
/// In general, if you're looking at this, don't overthink these -- just slap
|
||||
/// a '_token` as their binding name and allow them to drop.
|
||||
macro_rules! create_token {
|
||||
(
|
||||
$(#[$struct_meta:meta])*
|
||||
$v:vis struct $token_name:ident<'ui>;
|
||||
|
||||
$(#[$end_meta:meta])*
|
||||
drop { $on_drop:expr }
|
||||
) => {
|
||||
#[must_use]
|
||||
$(#[$struct_meta])*
|
||||
pub struct $token_name<'a>($crate::__core::marker::PhantomData<crate::Ui<'a>>);
|
||||
|
||||
impl<'a> $token_name<'a> {
|
||||
/// Creates a new token type.
|
||||
pub(crate) fn new(_: &crate::Ui<'a>) -> Self {
|
||||
Self(std::marker::PhantomData)
|
||||
}
|
||||
|
||||
$(#[$end_meta])*
|
||||
#[inline]
|
||||
pub fn end(self) {
|
||||
// left empty for drop
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for $token_name<'_> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { $on_drop }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,7 @@
|
||||
use bitflags::bitflags;
|
||||
use std::borrow::Cow;
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
@ -141,7 +139,7 @@ impl<'a> ComboBox<'a> {
|
||||
///
|
||||
/// Returns `None` if the combo box is not open and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin(self, ui: &Ui) -> Option<ComboBoxToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ComboBoxToken<'ui>> {
|
||||
let should_render = unsafe {
|
||||
sys::igBeginCombo(
|
||||
self.label.as_ptr(),
|
||||
@ -150,7 +148,7 @@ impl<'a> ComboBox<'a> {
|
||||
)
|
||||
};
|
||||
if should_render {
|
||||
Some(ComboBoxToken { ctx: ui.ctx })
|
||||
Some(ComboBoxToken::new(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -159,34 +157,20 @@ impl<'a> ComboBox<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if the combo box is not open.
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(combo) = self.begin(ui) {
|
||||
if let Some(_combo) = self.begin(ui) {
|
||||
f();
|
||||
combo.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a combo box that must be ended by calling `.end()`
|
||||
#[must_use]
|
||||
pub struct ComboBoxToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a combo box that can be ended by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct ComboBoxToken<'ui>;
|
||||
|
||||
impl ComboBoxToken {
|
||||
/// Ends a combo box
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndCombo() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ComboBoxToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A ComboBoxToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
drop { sys::igEndCombo() }
|
||||
);
|
||||
|
||||
/// # Convenience functions
|
||||
impl<'a> ComboBox<'a> {
|
||||
@ -219,7 +203,6 @@ impl<'a> ComboBox<'a> {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
_cb.end(ui);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@ -1,8 +1,5 @@
|
||||
use std::borrow::Cow;
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
@ -62,7 +59,7 @@ impl<'a> ListBox<'a> {
|
||||
///
|
||||
/// Returns `None` if the list box is not open and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin(self, ui: &Ui) -> Option<ListBoxToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ListBoxToken<'ui>> {
|
||||
let should_render = unsafe {
|
||||
match self.size {
|
||||
Size::Vec(size) => sys::igListBoxHeaderVec2(self.label.as_ptr(), size),
|
||||
@ -73,7 +70,7 @@ impl<'a> ListBox<'a> {
|
||||
}
|
||||
};
|
||||
if should_render {
|
||||
Some(ListBoxToken { ctx: ui.ctx })
|
||||
Some(ListBoxToken::new(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -82,34 +79,20 @@ impl<'a> ListBox<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if the list box is not open.
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(list) = self.begin(ui) {
|
||||
if let Some(_list) = self.begin(ui) {
|
||||
f();
|
||||
list.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a list box that must be ended by calling `.end()`
|
||||
#[must_use]
|
||||
pub struct ListBoxToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a list box that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct ListBoxToken<'ui>;
|
||||
|
||||
impl ListBoxToken {
|
||||
/// Ends a list box
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igListBoxFooter() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ListBoxToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A ListBoxToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
drop { sys::igListBoxFooter() }
|
||||
);
|
||||
|
||||
/// # Convenience functions
|
||||
impl<'a> ListBox<'a> {
|
||||
@ -136,7 +119,6 @@ impl<'a> ListBox<'a> {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
_cb.end(ui);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
@ -15,9 +13,9 @@ impl<'ui> Ui<'ui> {
|
||||
///
|
||||
/// Returns `None` if the menu bar is not visible and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin_main_menu_bar(&self) -> Option<MainMenuBarToken> {
|
||||
pub fn begin_main_menu_bar(&self) -> Option<MainMenuBarToken<'ui>> {
|
||||
if unsafe { sys::igBeginMainMenuBar() } {
|
||||
Some(MainMenuBarToken { ctx: self.ctx })
|
||||
Some(MainMenuBarToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -26,9 +24,8 @@ impl<'ui> Ui<'ui> {
|
||||
///
|
||||
/// Note: the closure is not called if the menu bar is not visible.
|
||||
pub fn main_menu_bar<F: FnOnce()>(&self, f: F) {
|
||||
if let Some(menu_bar) = self.begin_main_menu_bar() {
|
||||
if let Some(_menu_bar) = self.begin_main_menu_bar() {
|
||||
f();
|
||||
menu_bar.end(self);
|
||||
}
|
||||
}
|
||||
/// Creates and starts appending to the menu bar of the current window.
|
||||
@ -38,9 +35,9 @@ impl<'ui> Ui<'ui> {
|
||||
///
|
||||
/// Returns `None` if the menu bar is not visible and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin_menu_bar(&self) -> Option<MenuBarToken> {
|
||||
pub fn begin_menu_bar(&self) -> Option<MenuBarToken<'_>> {
|
||||
if unsafe { sys::igBeginMenuBar() } {
|
||||
Some(MenuBarToken { ctx: self.ctx })
|
||||
Some(MenuBarToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -49,9 +46,8 @@ impl<'ui> Ui<'ui> {
|
||||
///
|
||||
/// Note: the closure is not called if the menu bar is not visible.
|
||||
pub fn menu_bar<F: FnOnce()>(&self, f: F) {
|
||||
if let Some(menu_bar) = self.begin_menu_bar() {
|
||||
if let Some(_menu_bar) = self.begin_menu_bar() {
|
||||
f();
|
||||
menu_bar.end(self);
|
||||
}
|
||||
}
|
||||
/// Creates and starts appending to a sub-menu entry.
|
||||
@ -61,9 +57,9 @@ 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<MenuToken> {
|
||||
pub fn begin_menu(&self, label: &ImStr, enabled: bool) -> Option<MenuToken<'_>> {
|
||||
if unsafe { sys::igBeginMenu(label.as_ptr(), enabled) } {
|
||||
Some(MenuToken { ctx: self.ctx })
|
||||
Some(MenuToken::new(self))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -72,9 +68,8 @@ impl<'ui> Ui<'ui> {
|
||||
///
|
||||
/// Note: the closure is not called if the menu is not visible.
|
||||
pub fn menu<F: FnOnce()>(&self, label: &ImStr, enabled: bool, f: F) {
|
||||
if let Some(menu) = self.begin_menu(label, enabled) {
|
||||
if let Some(_menu) = self.begin_menu(label, enabled) {
|
||||
f();
|
||||
menu.end(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,68 +146,29 @@ impl<'a> MenuItem<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a main menu bar that must be ended by calling `.end()`
|
||||
#[must_use]
|
||||
pub struct MainMenuBarToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a main menu bar that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct MainMenuBarToken<'ui>;
|
||||
|
||||
impl MainMenuBarToken {
|
||||
/// Ends a main menu bar
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndMainMenuBar() };
|
||||
}
|
||||
}
|
||||
drop { sys::igEndMainMenuBar() }
|
||||
);
|
||||
|
||||
impl Drop for MainMenuBarToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A MainMenuBarToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a menu bar that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct MenuBarToken<'ui>;
|
||||
|
||||
/// Tracks a menu bar that must be ended by calling `.end()`
|
||||
#[must_use]
|
||||
pub struct MenuBarToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl MenuBarToken {
|
||||
/// Ends a menu bar
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndMenuBar() };
|
||||
}
|
||||
}
|
||||
drop { sys::igEndMenuBar() }
|
||||
);
|
||||
|
||||
impl Drop for MenuBarToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A MenuBarToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a menu that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct MenuToken<'ui>;
|
||||
|
||||
/// Tracks a menu that must be ended by calling `.end()`
|
||||
#[must_use]
|
||||
pub struct MenuToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
|
||||
impl MenuToken {
|
||||
/// Ends a menu
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndMenu() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MenuToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A MenuToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
drop { sys::igEndMenu() }
|
||||
);
|
||||
|
||||
@ -19,12 +19,11 @@
|
||||
//! ```
|
||||
//!
|
||||
//! See `test_window_impl.rs` for a more complicated example.
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::Ui;
|
||||
use bitflags::bitflags;
|
||||
use std::{ptr, thread};
|
||||
use std::ptr;
|
||||
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
@ -90,12 +89,12 @@ impl<'a> TabBar<'a> {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn begin(self, ui: &Ui) -> Option<TabBarToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<TabBarToken<'ui>> {
|
||||
let should_render =
|
||||
unsafe { sys::igBeginTabBar(self.id.as_ptr(), self.flags.bits() as i32) };
|
||||
|
||||
if should_render {
|
||||
Some(TabBarToken { ctx: ui.ctx })
|
||||
Some(TabBarToken::new(ui))
|
||||
} else {
|
||||
unsafe { sys::igEndTabBar() };
|
||||
None
|
||||
@ -106,33 +105,20 @@ impl<'a> TabBar<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if no tabbar content is visible
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(tab) = self.begin(ui) {
|
||||
if let Some(_tab) = self.begin(ui) {
|
||||
f();
|
||||
tab.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a window that must be ended by calling `.end()`
|
||||
pub struct TabBarToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a window that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct TabBarToken<'ui>;
|
||||
|
||||
impl TabBarToken {
|
||||
/// Ends a tab bar
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndTabBar() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TabBarToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A TabBarToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Ends a tab bar.
|
||||
drop { sys::igEndTabBar() }
|
||||
);
|
||||
|
||||
pub struct TabItem<'a> {
|
||||
name: &'a ImStr,
|
||||
@ -168,7 +154,7 @@ impl<'a> TabItem<'a> {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn begin(self, ui: &Ui) -> Option<TabItemToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<TabItemToken<'ui>> {
|
||||
let should_render = unsafe {
|
||||
sys::igBeginTabItem(
|
||||
self.name.as_ptr(),
|
||||
@ -180,7 +166,7 @@ impl<'a> TabItem<'a> {
|
||||
};
|
||||
|
||||
if should_render {
|
||||
Some(TabItemToken { ctx: ui.ctx })
|
||||
Some(TabItemToken::new(ui))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -190,28 +176,17 @@ impl<'a> TabItem<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if the tab item is not selected
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(tab) = self.begin(ui) {
|
||||
if let Some(_tab) = self.begin(ui) {
|
||||
f();
|
||||
tab.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TabItemToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a tab bar item that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct TabItemToken<'ui>;
|
||||
|
||||
impl TabItemToken {
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndTabItem() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TabItemToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A TabItemToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Ends a tab bar item.
|
||||
drop { sys::igEndTabItem() }
|
||||
);
|
||||
|
||||
@ -26,14 +26,14 @@ impl<'ui> Ui<'ui> {
|
||||
pub fn text_colored<T: AsRef<str>>(&self, color: [f32; 4], text: T) {
|
||||
let style = self.push_style_color(StyleColor::Text, color);
|
||||
self.text(text);
|
||||
style.pop(self);
|
||||
style.end();
|
||||
}
|
||||
/// Renders simple text using `StyleColor::TextDisabled` color
|
||||
pub fn text_disabled<T: AsRef<str>>(&self, text: T) {
|
||||
let color = self.style_color(StyleColor::TextDisabled);
|
||||
let style = self.push_style_color(StyleColor::Text, color);
|
||||
self.text(text);
|
||||
style.pop(self);
|
||||
style.end();
|
||||
}
|
||||
/// Renders text wrapped to the end of window (or column)
|
||||
pub fn text_wrapped(&self, text: &ImStr) {
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
use bitflags::bitflags;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::{Condition, Ui};
|
||||
@ -234,11 +231,10 @@ impl<'a> TreeNode<'a> {
|
||||
/// Pushes a tree node and starts appending to it.
|
||||
///
|
||||
/// Returns `Some(TreeNodeToken)` if the tree node is open. After content has been
|
||||
/// rendered, the token must be popped by calling `.pop()`.
|
||||
/// rendered, the token can be popped by calling `.pop()`.
|
||||
///
|
||||
/// Returns `None` if the tree node is not open and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn push(self, ui: &Ui) -> Option<TreeNodeToken> {
|
||||
pub fn push<'ui>(self, ui: &Ui<'ui>) -> Option<TreeNodeToken<'ui>> {
|
||||
let open = unsafe {
|
||||
if self.opened_cond != Condition::Never {
|
||||
sys::igSetNextItemOpen(self.opened, self.opened_cond as i32);
|
||||
@ -259,13 +255,10 @@ impl<'a> TreeNode<'a> {
|
||||
}
|
||||
};
|
||||
if open {
|
||||
Some(TreeNodeToken {
|
||||
ctx: if self.flags.contains(TreeNodeFlags::NO_TREE_PUSH_ON_OPEN) {
|
||||
ptr::null()
|
||||
} else {
|
||||
ui.ctx
|
||||
},
|
||||
})
|
||||
Some(TreeNodeToken::new(
|
||||
ui,
|
||||
!self.flags.contains(TreeNodeFlags::NO_TREE_PUSH_ON_OPEN),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -274,37 +267,42 @@ impl<'a> TreeNode<'a> {
|
||||
///
|
||||
/// Note: the closure is not called if the tree node is not open.
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(node) = self.push(ui) {
|
||||
if let Some(_node) = self.push(ui) {
|
||||
f();
|
||||
node.pop(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a tree node that must be popped by calling `.pop()`.
|
||||
/// Tracks a tree node that can be popped by calling `.pop()`, `end()`, or by dropping.
|
||||
///
|
||||
/// If `TreeNodeFlags::NO_TREE_PUSH_ON_OPEN` was used when this token was created, calling `.pop()`
|
||||
/// is not mandatory and is a no-op.
|
||||
#[must_use]
|
||||
pub struct TreeNodeToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
pub struct TreeNodeToken<'a>(core::marker::PhantomData<crate::Ui<'a>>, bool);
|
||||
|
||||
impl<'a> TreeNodeToken<'a> {
|
||||
/// Creates a new token type. This takes a bool for the no-op variant on NO_TREE_PUSH_ON_OPEN.
|
||||
pub(crate) fn new(_: &crate::Ui<'a>, execute_drop: bool) -> Self {
|
||||
Self(std::marker::PhantomData, execute_drop)
|
||||
}
|
||||
|
||||
impl TreeNodeToken {
|
||||
/// Pops a tree node
|
||||
#[inline]
|
||||
pub fn pop(mut self, _: &Ui) {
|
||||
if !self.ctx.is_null() {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igTreePop() };
|
||||
}
|
||||
pub fn end(self) {
|
||||
// left empty for drop
|
||||
}
|
||||
|
||||
/// Pops a tree node
|
||||
#[inline]
|
||||
pub fn pop(self) {
|
||||
self.end()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TreeNodeToken {
|
||||
impl Drop for TreeNodeToken<'_> {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A TreeNodeToken was leaked. Did you call .pop()?");
|
||||
if self.1 {
|
||||
unsafe { sys::igTreePop() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,6 @@
|
||||
use std::f32;
|
||||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::sys;
|
||||
use crate::window::WindowFlags;
|
||||
use crate::{Id, Ui};
|
||||
@ -244,7 +241,7 @@ impl<'a> ChildWindow<'a> {
|
||||
/// rendered, the token must be ended by calling `.end()`.
|
||||
///
|
||||
/// Returns `None` if the window is not visible and no content should be rendered.
|
||||
pub fn begin(self, ui: &Ui) -> Option<ChildWindowToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ChildWindowToken<'ui>> {
|
||||
if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 {
|
||||
unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) };
|
||||
}
|
||||
@ -269,7 +266,7 @@ impl<'a> ChildWindow<'a> {
|
||||
sys::igBeginChildID(id, self.size.into(), self.border, self.flags.bits() as i32)
|
||||
};
|
||||
if should_render {
|
||||
Some(ChildWindowToken { ctx: ui.ctx })
|
||||
Some(ChildWindowToken::new(ui))
|
||||
} else {
|
||||
unsafe { sys::igEndChild() };
|
||||
None
|
||||
@ -280,30 +277,17 @@ impl<'a> ChildWindow<'a> {
|
||||
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
|
||||
/// or fully clipped).
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(window) = self.begin(ui) {
|
||||
if let Some(_window) = self.begin(ui) {
|
||||
f();
|
||||
window.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a child window that must be ended by calling `.end()`
|
||||
pub struct ChildWindowToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a child window that can be ended by calling `.end()`
|
||||
/// or by dropping
|
||||
pub struct ChildWindowToken<'ui>;
|
||||
|
||||
impl ChildWindowToken {
|
||||
/// Ends a window
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEndChild() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ChildWindowToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A ChildWindowToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
drop { sys::igEndChild() }
|
||||
);
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
use bitflags::bitflags;
|
||||
use std::f32;
|
||||
use std::ptr;
|
||||
use std::thread;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::string::ImStr;
|
||||
use crate::sys;
|
||||
use crate::{Condition, Ui};
|
||||
@ -482,7 +480,7 @@ impl<'a> Window<'a> {
|
||||
///
|
||||
/// Returns `None` if the window is not visible and no content should be rendered.
|
||||
#[must_use]
|
||||
pub fn begin(self, ui: &Ui) -> Option<WindowToken> {
|
||||
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<WindowToken<'ui>> {
|
||||
if self.pos_cond != Condition::Never {
|
||||
unsafe {
|
||||
sys::igSetNextWindowPos(
|
||||
@ -528,7 +526,7 @@ impl<'a> Window<'a> {
|
||||
)
|
||||
};
|
||||
if should_render {
|
||||
Some(WindowToken { ctx: ui.ctx })
|
||||
Some(WindowToken::new(ui))
|
||||
} else {
|
||||
unsafe { sys::igEnd() };
|
||||
None
|
||||
@ -539,30 +537,17 @@ impl<'a> Window<'a> {
|
||||
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
|
||||
/// or fully clipped).
|
||||
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
|
||||
if let Some(window) = self.begin(ui) {
|
||||
if let Some(_window) = self.begin(ui) {
|
||||
f();
|
||||
window.end(ui);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tracks a window that must be ended by calling `.end()`
|
||||
pub struct WindowToken {
|
||||
ctx: *const Context,
|
||||
}
|
||||
create_token!(
|
||||
/// Tracks a window that can be ended by calling `.end()`
|
||||
/// or by dropping.
|
||||
pub struct WindowToken<'ui>;
|
||||
|
||||
impl WindowToken {
|
||||
/// Ends a window
|
||||
pub fn end(mut self, _: &Ui) {
|
||||
self.ctx = ptr::null();
|
||||
unsafe { sys::igEnd() };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WindowToken {
|
||||
fn drop(&mut self) {
|
||||
if !self.ctx.is_null() && !thread::panicking() {
|
||||
panic!("A WindowToken was leaked. Did you call .end()?");
|
||||
}
|
||||
}
|
||||
}
|
||||
drop { sys::igEnd() }
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user