dear_imgui_rs/widget/
tab.rs1#![allow(
7 clippy::cast_possible_truncation,
8 clippy::cast_sign_loss,
9 clippy::as_conversions
10)]
11use crate::sys;
12use crate::ui::Ui;
13use std::ptr;
14
15bitflags::bitflags! {
16 #[repr(transparent)]
18 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
19 pub struct TabBarFlags: i32 {
20 const NONE = 0;
22 const REORDERABLE = sys::ImGuiTabBarFlags_Reorderable as i32;
24 const AUTO_SELECT_NEW_TABS = sys::ImGuiTabBarFlags_AutoSelectNewTabs as i32;
26 const TAB_LIST_POPUP_BUTTON = sys::ImGuiTabBarFlags_TabListPopupButton as i32;
28 const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabBarFlags_NoCloseWithMiddleMouseButton as i32;
30 const NO_TAB_LIST_SCROLLING_BUTTONS = sys::ImGuiTabBarFlags_NoTabListScrollingButtons as i32;
32 const NO_TOOLTIP = sys::ImGuiTabBarFlags_NoTooltip as i32;
34 const DRAW_SELECTED_OVERLINE = sys::ImGuiTabBarFlags_DrawSelectedOverline as i32;
36 const FITTING_POLICY_MIXED = sys::ImGuiTabBarFlags_FittingPolicyMixed as i32;
38 const FITTING_POLICY_SHRINK = sys::ImGuiTabBarFlags_FittingPolicyShrink as i32;
40 const FITTING_POLICY_SCROLL = sys::ImGuiTabBarFlags_FittingPolicyScroll as i32;
42 const FITTING_POLICY_MASK = sys::ImGuiTabBarFlags_FittingPolicyMask_ as i32;
44 const FITTING_POLICY_DEFAULT = sys::ImGuiTabBarFlags_FittingPolicyDefault_ as i32;
46 }
47}
48
49bitflags::bitflags! {
50 #[repr(transparent)]
52 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
53 pub struct TabItemFlags: i32 {
54 const NONE = 0;
56 const UNSAVED_DOCUMENT = sys::ImGuiTabItemFlags_UnsavedDocument as i32;
58 const SET_SELECTED = sys::ImGuiTabItemFlags_SetSelected as i32;
60 const NO_CLOSE_WITH_MIDDLE_MOUSE_BUTTON = sys::ImGuiTabItemFlags_NoCloseWithMiddleMouseButton as i32;
62 const NO_PUSH_ID = sys::ImGuiTabItemFlags_NoPushId as i32;
64 const NO_TOOLTIP = sys::ImGuiTabItemFlags_NoTooltip as i32;
66 const NO_REORDER = sys::ImGuiTabItemFlags_NoReorder as i32;
68 const LEADING = sys::ImGuiTabItemFlags_Leading as i32;
70 const TRAILING = sys::ImGuiTabItemFlags_Trailing as i32;
72 }
73}
74
75#[derive(Debug)]
77#[must_use]
78pub struct TabBar<T> {
79 id: T,
80 flags: TabBarFlags,
81}
82
83impl<T: AsRef<str>> TabBar<T> {
84 #[doc(alias = "BeginTabBar")]
86 pub fn new(id: T) -> Self {
87 Self {
88 id,
89 flags: TabBarFlags::NONE,
90 }
91 }
92
93 pub fn reorderable(mut self, value: bool) -> Self {
97 if value {
98 self.flags |= TabBarFlags::REORDERABLE;
99 } else {
100 self.flags &= !TabBarFlags::REORDERABLE;
101 }
102 self
103 }
104
105 pub fn flags(mut self, flags: TabBarFlags) -> Self {
109 self.flags = flags;
110 self
111 }
112
113 pub fn begin(self, ui: &Ui) -> Option<TabBarToken<'_>> {
115 ui.tab_bar_with_flags(self.id, self.flags)
116 }
117
118 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
123 self.begin(ui).map(|_tab| f())
124 }
125}
126
127#[derive(Debug)]
129#[must_use]
130pub struct TabBarToken<'ui> {
131 ui: &'ui Ui,
132}
133
134impl<'ui> TabBarToken<'ui> {
135 pub(crate) fn new(ui: &'ui Ui) -> Self {
137 Self { ui }
138 }
139
140 pub fn end(self) {
142 }
144}
145
146impl<'ui> Drop for TabBarToken<'ui> {
147 fn drop(&mut self) {
148 unsafe {
149 sys::igEndTabBar();
150 }
151 }
152}
153
154#[derive(Debug)]
156#[must_use]
157pub struct TabItem<'a, T> {
158 label: T,
159 opened: Option<&'a mut bool>,
160 flags: TabItemFlags,
161}
162
163impl<'a, T: AsRef<str>> TabItem<'a, T> {
164 #[doc(alias = "BeginTabItem")]
166 pub fn new(label: T) -> Self {
167 Self {
168 label,
169 opened: None,
170 flags: TabItemFlags::NONE,
171 }
172 }
173
174 pub fn opened(mut self, opened: &'a mut bool) -> Self {
178 self.opened = Some(opened);
179 self
180 }
181
182 pub fn flags(mut self, flags: TabItemFlags) -> Self {
186 self.flags = flags;
187 self
188 }
189
190 pub fn begin(self, ui: &Ui) -> Option<TabItemToken<'_>> {
192 ui.tab_item_with_flags(self.label, self.opened, self.flags)
193 }
194
195 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
200 self.begin(ui).map(|_tab| f())
201 }
202}
203
204#[derive(Debug)]
206#[must_use]
207pub struct TabItemToken<'ui> {
208 ui: &'ui Ui,
209}
210
211impl<'ui> TabItemToken<'ui> {
212 pub(crate) fn new(ui: &'ui Ui) -> Self {
214 Self { ui }
215 }
216
217 pub fn end(self) {
219 }
221}
222
223impl<'ui> Drop for TabItemToken<'ui> {
224 fn drop(&mut self) {
225 unsafe {
226 sys::igEndTabItem();
227 }
228 }
229}
230
231impl Ui {
233 #[doc(alias = "BeginTabBar")]
237 pub fn tab_bar(&self, id: impl AsRef<str>) -> Option<TabBarToken<'_>> {
238 self.tab_bar_with_flags(id, TabBarFlags::NONE)
239 }
240
241 #[doc(alias = "BeginTabBar")]
244 pub fn tab_bar_with_flags(
245 &self,
246 id: impl AsRef<str>,
247 flags: TabBarFlags,
248 ) -> Option<TabBarToken<'_>> {
249 let id_ptr = self.scratch_txt(id);
250 let should_render = unsafe { sys::igBeginTabBar(id_ptr, flags.bits()) };
251
252 if should_render {
253 Some(TabBarToken::new(self))
254 } else {
255 None
256 }
257 }
258
259 #[doc(alias = "BeginTabItem")]
267 pub fn tab_item(&self, label: impl AsRef<str>) -> Option<TabItemToken<'_>> {
268 self.tab_item_with_flags(label, None, TabItemFlags::NONE)
269 }
270
271 #[doc(alias = "BeginTabItem")]
275 pub fn tab_item_with_opened(
276 &self,
277 label: impl AsRef<str>,
278 opened: &mut bool,
279 ) -> Option<TabItemToken<'_>> {
280 self.tab_item_with_flags(label, Some(opened), TabItemFlags::NONE)
281 }
282
283 #[doc(alias = "BeginTabItem")]
285 pub fn tab_item_with_flags(
286 &self,
287 label: impl AsRef<str>,
288 opened: Option<&mut bool>,
289 flags: TabItemFlags,
290 ) -> Option<TabItemToken<'_>> {
291 let label_ptr = self.scratch_txt(label);
292 let opened_ptr = opened.map(|x| x as *mut bool).unwrap_or(ptr::null_mut());
293
294 let should_render = unsafe { sys::igBeginTabItem(label_ptr, opened_ptr, flags.bits()) };
295
296 if should_render {
297 Some(TabItemToken::new(self))
298 } else {
299 None
300 }
301 }
302}