1#![allow(
2 clippy::cast_possible_truncation,
3 clippy::cast_sign_loss,
4 clippy::as_conversions
5)]
6use crate::sys;
7use crate::ui::Ui;
8use std::ptr;
9
10bitflags::bitflags! {
11 #[repr(transparent)]
13 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14 pub struct TabBarFlags: i32 {
15 const NONE = 0;
17 const REORDERABLE = sys::ImGuiTabBarFlags_Reorderable as i32;
19 const AUTO_SELECT_NEW_TABS = sys::ImGuiTabBarFlags_AutoSelectNewTabs as i32;
21 const TAB_LIST_POPUP_BUTTON = sys::ImGuiTabBarFlags_TabListPopupButton as i32;
23 const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabBarFlags_NoCloseWithMiddleMouseButton as i32;
25 const NO_TAB_LIST_SCROLLING_BUTTONS = sys::ImGuiTabBarFlags_NoTabListScrollingButtons as i32;
27 const NO_TOOLTIP = sys::ImGuiTabBarFlags_NoTooltip as i32;
29 const DRAW_SELECTED_OVERLINE = sys::ImGuiTabBarFlags_DrawSelectedOverline as i32;
31 const FITTING_POLICY_MIXED = sys::ImGuiTabBarFlags_FittingPolicyMixed as i32;
33 const FITTING_POLICY_SHRINK = sys::ImGuiTabBarFlags_FittingPolicyShrink as i32;
35 const FITTING_POLICY_SCROLL = sys::ImGuiTabBarFlags_FittingPolicyScroll as i32;
37 const FITTING_POLICY_MASK = sys::ImGuiTabBarFlags_FittingPolicyMask_ as i32;
39 const FITTING_POLICY_DEFAULT = sys::ImGuiTabBarFlags_FittingPolicyDefault_ as i32;
41 }
42}
43
44bitflags::bitflags! {
45 #[repr(transparent)]
47 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
48 pub struct TabItemFlags: i32 {
49 const NONE = 0;
51 const UNSAVED_DOCUMENT = sys::ImGuiTabItemFlags_UnsavedDocument as i32;
53 const SET_SELECTED = sys::ImGuiTabItemFlags_SetSelected as i32;
55 const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabItemFlags_NoCloseWithMiddleMouseButton as i32;
57 const NO_PUSH_ID = sys::ImGuiTabItemFlags_NoPushId as i32;
59 const NO_TOOLTIP = sys::ImGuiTabItemFlags_NoTooltip as i32;
61 const NO_REORDER = sys::ImGuiTabItemFlags_NoReorder as i32;
63 const LEADING = sys::ImGuiTabItemFlags_Leading as i32;
65 const TRAILING = sys::ImGuiTabItemFlags_Trailing as i32;
67 }
68}
69
70#[derive(Debug)]
72#[must_use]
73pub struct TabBar<T> {
74 id: T,
75 flags: TabBarFlags,
76}
77
78impl<T: AsRef<str>> TabBar<T> {
79 #[doc(alias = "BeginTabBar")]
81 pub fn new(id: T) -> Self {
82 Self {
83 id,
84 flags: TabBarFlags::NONE,
85 }
86 }
87
88 pub fn reorderable(mut self, value: bool) -> Self {
92 if value {
93 self.flags |= TabBarFlags::REORDERABLE;
94 } else {
95 self.flags &= !TabBarFlags::REORDERABLE;
96 }
97 self
98 }
99
100 pub fn flags(mut self, flags: TabBarFlags) -> Self {
104 self.flags = flags;
105 self
106 }
107
108 pub fn begin(self, ui: &Ui) -> Option<TabBarToken<'_>> {
110 ui.tab_bar_with_flags(self.id, self.flags)
111 }
112
113 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
118 self.begin(ui).map(|_tab| f())
119 }
120}
121
122#[derive(Debug)]
124#[must_use]
125pub struct TabBarToken<'ui> {
126 ui: &'ui Ui,
127}
128
129impl<'ui> TabBarToken<'ui> {
130 pub(crate) fn new(ui: &'ui Ui) -> Self {
132 Self { ui }
133 }
134
135 pub fn end(self) {
137 }
139}
140
141impl<'ui> Drop for TabBarToken<'ui> {
142 fn drop(&mut self) {
143 unsafe {
144 sys::igEndTabBar();
145 }
146 }
147}
148
149#[derive(Debug)]
151#[must_use]
152pub struct TabItem<'a, T> {
153 label: T,
154 opened: Option<&'a mut bool>,
155 flags: TabItemFlags,
156}
157
158impl<'a, T: AsRef<str>> TabItem<'a, T> {
159 #[doc(alias = "BeginTabItem")]
161 pub fn new(label: T) -> Self {
162 Self {
163 label,
164 opened: None,
165 flags: TabItemFlags::NONE,
166 }
167 }
168
169 pub fn opened(mut self, opened: &'a mut bool) -> Self {
173 self.opened = Some(opened);
174 self
175 }
176
177 pub fn flags(mut self, flags: TabItemFlags) -> Self {
181 self.flags = flags;
182 self
183 }
184
185 pub fn begin(self, ui: &Ui) -> Option<TabItemToken<'_>> {
187 ui.tab_item_with_flags(self.label, self.opened, self.flags)
188 }
189
190 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
195 self.begin(ui).map(|_tab| f())
196 }
197}
198
199#[derive(Debug)]
201#[must_use]
202pub struct TabItemToken<'ui> {
203 ui: &'ui Ui,
204}
205
206impl<'ui> TabItemToken<'ui> {
207 pub(crate) fn new(ui: &'ui Ui) -> Self {
209 Self { ui }
210 }
211
212 pub fn end(self) {
214 }
216}
217
218impl<'ui> Drop for TabItemToken<'ui> {
219 fn drop(&mut self) {
220 unsafe {
221 sys::igEndTabItem();
222 }
223 }
224}
225
226impl Ui {
228 #[doc(alias = "BeginTabBar")]
232 pub fn tab_bar(&self, id: impl AsRef<str>) -> Option<TabBarToken<'_>> {
233 self.tab_bar_with_flags(id, TabBarFlags::NONE)
234 }
235
236 #[doc(alias = "BeginTabBar")]
239 pub fn tab_bar_with_flags(
240 &self,
241 id: impl AsRef<str>,
242 flags: TabBarFlags,
243 ) -> Option<TabBarToken<'_>> {
244 let id_ptr = self.scratch_txt(id);
245 let should_render = unsafe { sys::igBeginTabBar(id_ptr, flags.bits()) };
246
247 if should_render {
248 Some(TabBarToken::new(self))
249 } else {
250 None
251 }
252 }
253
254 #[doc(alias = "BeginTabItem")]
262 pub fn tab_item(&self, label: impl AsRef<str>) -> Option<TabItemToken<'_>> {
263 self.tab_item_with_flags(label, None, TabItemFlags::NONE)
264 }
265
266 #[doc(alias = "BeginTabItem")]
270 pub fn tab_item_with_opened(
271 &self,
272 label: impl AsRef<str>,
273 opened: &mut bool,
274 ) -> Option<TabItemToken<'_>> {
275 self.tab_item_with_flags(label, Some(opened), TabItemFlags::NONE)
276 }
277
278 #[doc(alias = "BeginTabItem")]
280 pub fn tab_item_with_flags(
281 &self,
282 label: impl AsRef<str>,
283 opened: Option<&mut bool>,
284 flags: TabItemFlags,
285 ) -> Option<TabItemToken<'_>> {
286 let label_ptr = self.scratch_txt(label);
287 let opened_ptr = opened.map(|x| x as *mut bool).unwrap_or(ptr::null_mut());
288
289 let should_render = unsafe { sys::igBeginTabItem(label_ptr, opened_ptr, flags.bits()) };
290
291 if should_render {
292 Some(TabItemToken::new(self))
293 } else {
294 None
295 }
296 }
297}