//! # Examples // //! ```no_run //! # use imgui::*; //! # let mut ctx = Context::create(); //! # let ui = ctx.frame(); //! //! // During UI construction //! TabBar::new("tabbar").build(&ui, || { //! TabItem::new("a tab").build(&ui, || { //! ui.text("tab content 1"); //! }); //! TabItem::new("2tab").build(&ui, || { //! ui.text("tab content 2"); //! }); //! }); //! ``` //! //! See `test_window_impl.rs` for a more complicated example. use crate::sys; use crate::Ui; use bitflags::bitflags; use std::ptr; bitflags! { #[repr(transparent)] pub struct TabBarFlags: u32 { const REORDERABLE = sys::ImGuiTabBarFlags_Reorderable; const AUTO_SELECT_NEW_TABS = sys::ImGuiTabBarFlags_AutoSelectNewTabs; const TAB_LIST_POPUP_BUTTON = sys::ImGuiTabBarFlags_TabListPopupButton; const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabBarFlags_NoCloseWithMiddleMouseButton; const NO_TAB_LIST_SCROLLING_BUTTONS = sys::ImGuiTabBarFlags_NoTabListScrollingButtons; const NO_TOOLTIP = sys::ImGuiTabBarFlags_NoTooltip; const FITTING_POLICY_RESIZE_DOWN = sys::ImGuiTabBarFlags_FittingPolicyResizeDown; const FITTING_POLICY_SCROLL = sys::ImGuiTabBarFlags_FittingPolicyScroll; const FITTING_POLICY_MASK = sys::ImGuiTabBarFlags_FittingPolicyMask_; const FITTING_POLICY_DEFAULT = sys::ImGuiTabBarFlags_FittingPolicyDefault_; } } bitflags! { #[repr(transparent)] pub struct TabItemFlags: u32 { const UNSAVED_DOCUMENT = sys::ImGuiTabItemFlags_UnsavedDocument; const SET_SELECTED = sys::ImGuiTabItemFlags_SetSelected; const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabItemFlags_NoCloseWithMiddleMouseButton; const NO_PUSH_ID = sys::ImGuiTabItemFlags_NoPushId; const NO_TOOLTIP = sys::ImGuiTabItemFlags_NoTooltip; const NO_REORDER = sys::ImGuiTabItemFlags_NoReorder; const LEADING = sys::ImGuiTabItemFlags_Leading; const TRAILING = sys::ImGuiTabItemFlags_Trailing; } } /// Builder for a tab bar. pub struct TabBar { id: T, flags: TabBarFlags, } impl> TabBar { #[inline] #[doc(alias = "BeginTabBar")] pub fn new(id: T) -> Self { Self { id, flags: TabBarFlags::empty(), } } /// Enable/Disable the reorderable property /// /// Disabled by default #[inline] pub fn reorderable(mut self, value: bool) -> Self { self.flags.set(TabBarFlags::REORDERABLE, value); self } /// Set the flags of the tab bar. /// /// Flags are empty by default #[inline] pub fn flags(mut self, flags: TabBarFlags) -> Self { self.flags = flags; self } #[must_use] pub fn begin(self, ui: &Ui) -> Option> { ui.tab_bar_with_flags(self.id, self.flags) } /// Creates a tab bar and runs a closure to construct the contents. /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if no tabbar content is visible pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } create_token!( /// Tracks a window that can be ended by calling `.end()` /// or by dropping pub struct TabBarToken<'ui>; /// Ends a tab bar. drop { sys::igEndTabBar() } ); pub struct TabItem<'a, T> { label: T, opened: Option<&'a mut bool>, flags: TabItemFlags, } impl<'a, T: AsRef> TabItem<'a, T> { #[doc(alias = "BeginTabItem")] pub fn new(name: T) -> Self { Self { label: name, opened: None, flags: TabItemFlags::empty(), } } /// Will open or close the tab. /// /// True to display the tab. Tab item is visible by default. #[inline] pub fn opened(mut self, opened: &'a mut bool) -> Self { self.opened = Some(opened); self } /// Set the flags of the tab item. /// /// Flags are empty by default #[inline] pub fn flags(mut self, flags: TabItemFlags) -> Self { self.flags = flags; self } #[must_use] pub fn begin(self, ui: &Ui) -> Option> { ui.tab_item_with_flags(self.label, self.opened, self.flags) } /// Creates a tab item and runs a closure to construct the contents. /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the tab item is not selected pub fn build R>(self, ui: &Ui, f: F) -> Option { self.begin(ui).map(|_tab| f()) } } create_token!( /// Tracks a tab bar item that can be ended by calling `.end()` /// or by dropping pub struct TabItemToken<'ui>; /// Ends a tab bar item. drop { sys::igEndTabItem() } ); impl Ui { /// Creates a tab bar and returns a tab bar token, allowing you to append /// Tab items afterwards. This passes no flags. To pass flags explicitly, /// use [tab_bar_with_flags](Self::tab_bar_with_flags). pub fn tab_bar(&self, id: impl AsRef) -> Option> { self.tab_bar_with_flags(id, TabBarFlags::empty()) } // /// Creates a tab bar and returns a tab bar token, allowing you to append /// Tab items afterwards. pub fn tab_bar_with_flags( &self, id: impl AsRef, flags: TabBarFlags, ) -> Option> { let should_render = unsafe { sys::igBeginTabBar(self.scratch_txt(id), flags.bits() as i32) }; if should_render { Some(TabBarToken::new(self)) } else { unsafe { sys::igEndTabBar() }; None } } /// Creates a new tab item and returns a token if its contents are visible. /// /// By default, this doesn't pass an opened bool nor any flags. See [tab_item_with_opened] /// and [tab_item_with_flags] for more. /// /// [tab_item_with_opened]: Self::tab_item_with_opened /// [tab_item_with_flags]: Self::tab_item_with_flags pub fn tab_item(&self, label: impl AsRef) -> Option> { self.tab_item_with_flags(label, None, TabItemFlags::empty()) } /// Creates a new tab item and returns a token if its contents are visible. /// /// By default, this doesn't pass any flags. See `[tab_item_with_flags]` for more. pub fn tab_item_with_opened( &self, label: impl AsRef, opened: &mut bool, ) -> Option> { self.tab_item_with_flags(label, Some(opened), TabItemFlags::empty()) } /// Creates a new tab item and returns a token if its contents are visible. pub fn tab_item_with_flags( &self, label: impl AsRef, opened: Option<&mut bool>, flags: TabItemFlags, ) -> Option> { let should_render = unsafe { sys::igBeginTabItem( self.scratch_txt(label), opened.map(|x| x as *mut bool).unwrap_or(ptr::null_mut()), flags.bits() as i32, ) }; if should_render { Some(TabItemToken::new(self)) } else { None } } }