Skip to main content

dear_imgui_rs/widget/
mod.rs

1//! Standard widgets
2//!
3//! Collection of common Dear ImGui widgets exposed with an idiomatic Rust
4//! API. Most widgets follow a small builder pattern for configuration, and
5//! also provide convenience methods on [`Ui`].
6//!
7//! Examples:
8//! ```no_run
9//! # use dear_imgui_rs::*;
10//! # let mut ctx = Context::create();
11//! # let ui = ctx.frame();
12//! // Buttons
13//! if ui.button("Click me") { /* ... */ }
14//!
15//! // Sliders
16//! let mut value = 0.5f32;
17//! ui.slider_f32("Value", &mut value, 0.0, 1.0);
18//!
19//! // Inputs
20//! let mut text = String::new();
21//! ui.input_text("Name", &mut text).build();
22//! ```
23//!
24//! Submodules group related widgets: `button`, `color`, `combo`, `drag`,
25//! `image`, `input`, `list_box`, `menu`, `misc`, `plot`, `popup`, `progress`,
26//! `selectable`, `slider`, `tab`, `table`, `text`, `tooltip`, `tree`.
27//!
28use crate::sys;
29#[cfg(feature = "serde")]
30use serde::{Deserialize, Serialize};
31
32pub mod button;
33pub mod color;
34pub mod combo;
35pub mod drag;
36pub mod image;
37pub mod input;
38pub mod list_box;
39pub mod menu;
40pub mod misc;
41pub mod multi_select;
42pub mod plot;
43pub mod popup;
44pub mod progress;
45pub mod selectable;
46pub mod slider;
47pub mod tab;
48pub mod table;
49pub mod text;
50pub mod tooltip;
51pub mod tree;
52
53// Re-export important types
54pub use popup::PopupFlags;
55pub use table::{TableBgTarget, TableBuilder, TableColumnSetup};
56
57// Widget implementations
58pub use self::button::*;
59pub use self::color::*;
60pub use self::combo::*;
61pub use self::drag::*;
62pub use self::image::*;
63pub use self::input::*;
64pub use self::list_box::*;
65pub use self::menu::*;
66pub use self::misc::*;
67pub use self::multi_select::*;
68pub use self::plot::*;
69pub use self::popup::*;
70pub use self::progress::*;
71pub use self::selectable::*;
72pub use self::slider::*;
73pub use self::tab::*;
74pub use self::table::*;
75pub use self::tooltip::*;
76pub use self::tree::*;
77
78// ButtonFlags is defined in misc.rs and re-exported
79
80bitflags::bitflags! {
81    /// Flags for tree node widgets
82    #[repr(transparent)]
83    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
84    pub struct TreeNodeFlags: i32 {
85        /// No flags
86        const NONE = 0;
87        /// Draw as selected
88        const SELECTED = sys::ImGuiTreeNodeFlags_Selected as i32;
89        /// Draw frame with background (e.g. for CollapsingHeader)
90        const FRAMED = sys::ImGuiTreeNodeFlags_Framed as i32;
91        /// Hit testing to allow subsequent widgets to overlap this one
92        const ALLOW_ITEM_OVERLAP = sys::ImGuiTreeNodeFlags_AllowOverlap as i32;
93        /// Hit testing to allow subsequent widgets to overlap this one
94        const ALLOW_OVERLAP = sys::ImGuiTreeNodeFlags_AllowOverlap as i32;
95        /// Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack
96        const NO_TREE_PUSH_ON_OPEN = sys::ImGuiTreeNodeFlags_NoTreePushOnOpen as i32;
97        /// Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)
98        const NO_AUTO_OPEN_ON_LOG = sys::ImGuiTreeNodeFlags_NoAutoOpenOnLog as i32;
99        /// Default node to be open
100        const DEFAULT_OPEN = sys::ImGuiTreeNodeFlags_DefaultOpen as i32;
101        /// Need double-click to open node
102        const OPEN_ON_DOUBLE_CLICK = sys::ImGuiTreeNodeFlags_OpenOnDoubleClick as i32;
103        /// Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.
104        const OPEN_ON_ARROW = sys::ImGuiTreeNodeFlags_OpenOnArrow as i32;
105        /// No collapsing, no arrow (use as a convenience for leaf nodes)
106        const LEAF = sys::ImGuiTreeNodeFlags_Leaf as i32;
107        /// Display a bullet instead of arrow
108        const BULLET = sys::ImGuiTreeNodeFlags_Bullet as i32;
109        /// Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
110        const FRAME_PADDING = sys::ImGuiTreeNodeFlags_FramePadding as i32;
111        /// Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
112        const SPAN_AVAIL_WIDTH = sys::ImGuiTreeNodeFlags_SpanAvailWidth as i32;
113        /// Extend hit box to the left-most and right-most edges (bypass the indented area).
114        const SPAN_FULL_WIDTH = sys::ImGuiTreeNodeFlags_SpanFullWidth as i32;
115        /// Narrow hit box and hover highlight to the label text width.
116        const SPAN_LABEL_WIDTH = sys::ImGuiTreeNodeFlags_SpanLabelWidth as i32;
117        /// Label will span all columns of its container table.
118        const LABEL_SPAN_ALL_COLUMNS = sys::ImGuiTreeNodeFlags_LabelSpanAllColumns as i32;
119        /// (WIP) Nav: left direction goes to parent. Only for the tree node, not the tree push.
120        const NAV_LEFT_JUMPS_BACK_HERE = sys::ImGuiTreeNodeFlags_NavLeftJumpsToParent as i32;
121        /// Combination of Leaf and NoTreePushOnOpen
122        const COLLAPSING_HEADER =
123            Self::FRAMED.bits() | Self::NO_TREE_PUSH_ON_OPEN.bits() | Self::NO_AUTO_OPEN_ON_LOG.bits();
124        /// No tree hierarchy guide lines are drawn.
125        const DRAW_LINES_NONE = sys::ImGuiTreeNodeFlags_DrawLinesNone as i32;
126        /// Draw full tree hierarchy guide lines.
127        const DRAW_LINES_FULL = sys::ImGuiTreeNodeFlags_DrawLinesFull as i32;
128        /// Draw tree hierarchy guide lines only to nodes.
129        const DRAW_LINES_TO_NODES = sys::ImGuiTreeNodeFlags_DrawLinesToNodes as i32;
130    }
131}
132
133bitflags::bitflags! {
134    /// Independent flags for combo box widgets.
135    ///
136    /// Mutually exclusive preview and height choices are represented by
137    /// [`ComboBoxPreviewMode`] and [`ComboBoxHeight`].
138    #[repr(transparent)]
139    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
140    pub struct ComboBoxFlags: i32 {
141        /// No flags
142        const NONE = 0;
143        /// Align the popup toward the left by default
144        const POPUP_ALIGN_LEFT = sys::ImGuiComboFlags_PopupAlignLeft as i32;
145    }
146}
147
148/// Height policy for combo box popups.
149#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
150pub enum ComboBoxHeight {
151    /// Max roughly 4 items visible.
152    Small,
153    /// Max roughly 8 items visible.
154    Regular,
155    /// Max roughly 20 items visible.
156    Large,
157    /// As many fitting items as possible.
158    Largest,
159}
160
161impl ComboBoxHeight {
162    #[inline]
163    const fn raw(self) -> i32 {
164        match self {
165            Self::Small => sys::ImGuiComboFlags_HeightSmall as i32,
166            Self::Regular => sys::ImGuiComboFlags_HeightRegular as i32,
167            Self::Large => sys::ImGuiComboFlags_HeightLarge as i32,
168            Self::Largest => sys::ImGuiComboFlags_HeightLargest as i32,
169        }
170    }
171}
172
173/// Preview/arrow layout for a combo box.
174#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
175pub enum ComboBoxPreviewMode {
176    /// Standard preview box with arrow button.
177    #[default]
178    Preview,
179    /// Standard preview box without the square arrow button.
180    PreviewNoArrowButton,
181    /// Width dynamically calculated from preview contents.
182    PreviewFit,
183    /// Fit preview width without the square arrow button.
184    PreviewFitNoArrowButton,
185    /// Display only a square arrow button.
186    NoPreview,
187}
188
189impl ComboBoxPreviewMode {
190    #[inline]
191    const fn raw(self) -> i32 {
192        match self {
193            Self::Preview => 0,
194            Self::PreviewNoArrowButton => sys::ImGuiComboFlags_NoArrowButton as i32,
195            Self::PreviewFit => sys::ImGuiComboFlags_WidthFitPreview as i32,
196            Self::PreviewFitNoArrowButton => {
197                sys::ImGuiComboFlags_WidthFitPreview as i32
198                    | sys::ImGuiComboFlags_NoArrowButton as i32
199            }
200            Self::NoPreview => sys::ImGuiComboFlags_NoPreview as i32,
201        }
202    }
203}
204
205/// Complete combo box options assembled from independent flags and exclusive
206/// mode selections.
207#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
208pub struct ComboBoxOptions {
209    pub flags: ComboBoxFlags,
210    pub height: Option<ComboBoxHeight>,
211    pub preview_mode: ComboBoxPreviewMode,
212}
213
214impl Default for ComboBoxOptions {
215    fn default() -> Self {
216        Self::new()
217    }
218}
219
220impl ComboBoxOptions {
221    pub const fn new() -> Self {
222        Self {
223            flags: ComboBoxFlags::NONE,
224            height: None,
225            preview_mode: ComboBoxPreviewMode::Preview,
226        }
227    }
228
229    pub fn flags(mut self, flags: ComboBoxFlags) -> Self {
230        self.flags = flags;
231        self
232    }
233
234    pub fn height(mut self, height: ComboBoxHeight) -> Self {
235        self.height = Some(height);
236        self
237    }
238
239    pub fn preview_mode(mut self, mode: ComboBoxPreviewMode) -> Self {
240        self.preview_mode = mode;
241        self
242    }
243
244    pub fn bits(self) -> i32 {
245        self.raw()
246    }
247
248    #[inline]
249    pub(crate) fn raw(self) -> i32 {
250        self.flags.bits() | self.height.map_or(0, ComboBoxHeight::raw) | self.preview_mode.raw()
251    }
252
253    #[inline]
254    pub(crate) fn validate(self, caller: &str) {
255        let unsupported_flags = self.flags.bits() & !ComboBoxFlags::all().bits();
256        assert!(
257            unsupported_flags == 0,
258            "{caller} received non-independent ImGuiComboFlags bits: 0x{unsupported_flags:X}"
259        );
260        let bits = self.raw();
261        let height_mask = sys::ImGuiComboFlags_HeightMask_ as i32;
262        let no_arrow_button = sys::ImGuiComboFlags_NoArrowButton as i32;
263        let no_preview = sys::ImGuiComboFlags_NoPreview as i32;
264        let width_fit_preview = sys::ImGuiComboFlags_WidthFitPreview as i32;
265        let supported = ComboBoxFlags::all().bits() | height_mask | combo_preview_mask();
266        let unsupported = bits & !supported;
267        assert!(
268            unsupported == 0,
269            "{caller} received unsupported ImGuiComboFlags bits: 0x{unsupported:X}"
270        );
271        assert!(
272            bits & (no_arrow_button | no_preview) != (no_arrow_button | no_preview),
273            "{caller} cannot combine NO_ARROW_BUTTON with NO_PREVIEW"
274        );
275        assert!(
276            bits & width_fit_preview == 0 || bits & no_preview == 0,
277            "{caller} cannot combine WIDTH_FIT_PREVIEW with NO_PREVIEW"
278        );
279        assert!(
280            (bits & height_mask).count_ones() <= 1,
281            "{caller} accepts at most one combo height policy"
282        );
283    }
284}
285
286#[inline]
287const fn combo_preview_mask() -> i32 {
288    (sys::ImGuiComboFlags_NoArrowButton
289        | sys::ImGuiComboFlags_NoPreview
290        | sys::ImGuiComboFlags_WidthFitPreview) as i32
291}
292
293impl From<ComboBoxFlags> for ComboBoxOptions {
294    fn from(flags: ComboBoxFlags) -> Self {
295        Self::new().flags(flags)
296    }
297}
298
299bitflags::bitflags! {
300    /// Independent flags for table widgets.
301    ///
302    /// The table sizing policy is a single-choice setting represented by
303    /// [`TableSizingPolicy`].
304    #[repr(transparent)]
305    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
306    pub struct TableFlags: i32 {
307        /// No flags
308        const NONE = 0;
309        /// Enable resizing columns
310        const RESIZABLE = sys::ImGuiTableFlags_Resizable as i32;
311        /// Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
312        const REORDERABLE = sys::ImGuiTableFlags_Reorderable as i32;
313        /// Enable hiding/disabling columns in context menu
314        const HIDEABLE = sys::ImGuiTableFlags_Hideable as i32;
315        /// Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.
316        const SORTABLE = sys::ImGuiTableFlags_Sortable as i32;
317        /// Disable persisting columns order, width and sort settings in the .ini file
318        const NO_SAVED_SETTINGS = sys::ImGuiTableFlags_NoSavedSettings as i32;
319        /// Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
320        const CONTEXT_MENU_IN_BODY = sys::ImGuiTableFlags_ContextMenuInBody as i32;
321        /// Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
322        const ROW_BG = sys::ImGuiTableFlags_RowBg as i32;
323        /// Draw horizontal borders between rows
324        const BORDERS_INNER_H = sys::ImGuiTableFlags_BordersInnerH as i32;
325        /// Draw horizontal borders at the top and bottom
326        const BORDERS_OUTER_H = sys::ImGuiTableFlags_BordersOuterH as i32;
327        /// Draw vertical borders between columns
328        const BORDERS_INNER_V = sys::ImGuiTableFlags_BordersInnerV as i32;
329        /// Draw vertical borders on the left and right sides
330        const BORDERS_OUTER_V = sys::ImGuiTableFlags_BordersOuterV as i32;
331        /// Draw horizontal borders
332        const BORDERS_H = Self::BORDERS_INNER_H.bits() | Self::BORDERS_OUTER_H.bits();
333        /// Draw vertical borders
334        const BORDERS_V = Self::BORDERS_INNER_V.bits() | Self::BORDERS_OUTER_V.bits();
335        /// Draw inner borders
336        const BORDERS_INNER = Self::BORDERS_INNER_V.bits() | Self::BORDERS_INNER_H.bits();
337        /// Draw outer borders
338        const BORDERS_OUTER = Self::BORDERS_OUTER_V.bits() | Self::BORDERS_OUTER_H.bits();
339        /// Draw all borders
340        const BORDERS = Self::BORDERS_INNER.bits() | Self::BORDERS_OUTER.bits();
341        /// [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style
342        const NO_BORDERS_IN_BODY = sys::ImGuiTableFlags_NoBordersInBody as i32;
343        /// [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style
344        const NO_BORDERS_IN_BODY_UNTIL_RESIZE = sys::ImGuiTableFlags_NoBordersInBodyUntilResize as i32;
345        /// Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used.
346        const NO_HOST_EXTEND_X = sys::ImGuiTableFlags_NoHostExtendX as i32;
347        /// Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible.
348        const NO_HOST_EXTEND_Y = sys::ImGuiTableFlags_NoHostExtendY as i32;
349        /// Disable keeping column always minimally visible when ScrollX is on and table gets too small. Not recommended if columns are resizable.
350        const NO_KEEP_COLUMNS_VISIBLE = sys::ImGuiTableFlags_NoKeepColumnsVisible as i32;
351        /// Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.
352        const PRECISE_WIDTHS = sys::ImGuiTableFlags_PreciseWidths as i32;
353        /// Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().
354        const NO_CLIP = sys::ImGuiTableFlags_NoClip as i32;
355        /// Default if BordersOuterV is on. Enable outer-most padding. Generally desirable if you have headers.
356        const PAD_OUTER_X = sys::ImGuiTableFlags_PadOuterX as i32;
357        /// Default if BordersOuterV is off. Disable outer-most padding.
358        const NO_PAD_OUTER_X = sys::ImGuiTableFlags_NoPadOuterX as i32;
359        /// Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).
360        const NO_PAD_INNER_X = sys::ImGuiTableFlags_NoPadInnerX as i32;
361        /// Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this creates a child window, ScrollY is currently generally recommended when using ScrollX.
362        const SCROLL_X = sys::ImGuiTableFlags_ScrollX as i32;
363        /// Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
364        const SCROLL_Y = sys::ImGuiTableFlags_ScrollY as i32;
365        /// Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
366        const SORT_MULTI = sys::ImGuiTableFlags_SortMulti as i32;
367        /// Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
368        const SORT_TRISTATE = sys::ImGuiTableFlags_SortTristate as i32;
369        /// Highlight column headers when hovered (may not be visible if table header is declaring a background color)
370        const HIGHLIGHT_HOVERED_COLUMN = sys::ImGuiTableFlags_HighlightHoveredColumn as i32;
371    }
372}
373
374/// Single-choice table sizing policy.
375#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
376pub enum TableSizingPolicy {
377    /// Columns default to fixed/auto widths matching contents width.
378    FixedFit,
379    /// Fixed/auto widths matching the maximum contents width of all columns.
380    FixedSame,
381    /// Stretch columns with weights proportional to contents widths.
382    StretchProp,
383    /// Stretch columns with equal weights unless overridden per column.
384    StretchSame,
385}
386
387impl TableSizingPolicy {
388    #[inline]
389    const fn raw(self) -> i32 {
390        match self {
391            Self::FixedFit => sys::ImGuiTableFlags_SizingFixedFit as i32,
392            Self::FixedSame => sys::ImGuiTableFlags_SizingFixedSame as i32,
393            Self::StretchProp => sys::ImGuiTableFlags_SizingStretchProp as i32,
394            Self::StretchSame => sys::ImGuiTableFlags_SizingStretchSame as i32,
395        }
396    }
397}
398
399/// Complete table options assembled from independent flags and an optional
400/// single sizing policy.
401#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
402pub struct TableOptions {
403    pub flags: TableFlags,
404    pub sizing_policy: Option<TableSizingPolicy>,
405}
406
407impl Default for TableOptions {
408    fn default() -> Self {
409        Self::new()
410    }
411}
412
413impl TableOptions {
414    pub const fn new() -> Self {
415        Self {
416            flags: TableFlags::NONE,
417            sizing_policy: None,
418        }
419    }
420
421    pub fn flags(mut self, flags: TableFlags) -> Self {
422        self.flags = flags;
423        self
424    }
425
426    pub fn sizing_policy(mut self, policy: TableSizingPolicy) -> Self {
427        self.sizing_policy = Some(policy);
428        self
429    }
430
431    pub fn bits(self) -> i32 {
432        self.raw()
433    }
434
435    #[inline]
436    pub(crate) fn raw(self) -> i32 {
437        self.flags.bits() | self.sizing_policy.map_or(0, TableSizingPolicy::raw)
438    }
439
440    #[inline]
441    pub(crate) fn validate(self, caller: &str) {
442        let unsupported_flags = self.flags.bits() & !TableFlags::all().bits();
443        assert!(
444            unsupported_flags == 0,
445            "{caller} received non-independent ImGuiTableFlags bits: 0x{unsupported_flags:X}"
446        );
447        let bits = self.raw();
448        let sizing_mask = sys::ImGuiTableFlags_SizingMask_ as i32;
449        let supported = TableFlags::all().bits() | sizing_mask;
450        let unsupported = bits & !supported;
451        assert!(
452            unsupported == 0,
453            "{caller} received unsupported ImGuiTableFlags bits: 0x{unsupported:X}"
454        );
455        let sizing_policy = bits & sizing_mask;
456        assert!(
457            is_valid_table_sizing_policy(sizing_policy),
458            "{caller} received invalid table sizing policy bits: 0x{sizing_policy:X}"
459        );
460    }
461}
462
463#[inline]
464const fn is_valid_table_sizing_policy(bits: i32) -> bool {
465    bits == 0
466        || bits == TableSizingPolicy::FixedFit.raw()
467        || bits == TableSizingPolicy::FixedSame.raw()
468        || bits == TableSizingPolicy::StretchProp.raw()
469        || bits == TableSizingPolicy::StretchSame.raw()
470}
471
472impl From<TableFlags> for TableOptions {
473    fn from(flags: TableFlags) -> Self {
474        Self::new().flags(flags)
475    }
476}
477
478#[cfg(feature = "serde")]
479impl Serialize for TableFlags {
480    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
481    where
482        S: serde::Serializer,
483    {
484        serializer.serialize_i32(self.bits())
485    }
486}
487
488#[cfg(feature = "serde")]
489impl<'de> Deserialize<'de> for TableFlags {
490    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
491    where
492        D: serde::Deserializer<'de>,
493    {
494        let bits = i32::deserialize(deserializer)?;
495        Ok(TableFlags::from_bits_truncate(bits))
496    }
497}
498
499bitflags::bitflags! {
500    /// Independent flags accepted by `TableSetupColumn()`.
501    ///
502    /// The fixed/stretch width mode and indent mode are single-choice settings
503    /// represented by [`TableColumnWidth`] and [`TableColumnIndent`].
504    #[repr(transparent)]
505    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
506    pub struct TableColumnFlags: i32 {
507        /// No flags
508        const NONE = 0;
509        /// Hide column and omit it from the context menu.
510        const DISABLED = sys::ImGuiTableColumnFlags_Disabled as i32;
511        /// Default to a hidden/disabled column.
512        const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide as i32;
513        /// Default to a sorting column.
514        const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort as i32;
515        /// Disable manual resizing
516        const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize as i32;
517        /// Disable manual reordering this column
518        const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder as i32;
519        /// Disable ability to hide/disable this column
520        const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide as i32;
521        /// Disable clipping for this column
522        const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip as i32;
523        /// Disable ability to sort on this field
524        const NO_SORT = sys::ImGuiTableColumnFlags_NoSort as i32;
525        /// Disable ability to sort in the ascending direction
526        const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending as i32;
527        /// Disable ability to sort in the descending direction
528        const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending as i32;
529        /// TableHeadersRow() will not submit label for this column
530        const NO_HEADER_LABEL = sys::ImGuiTableColumnFlags_NoHeaderLabel as i32;
531        /// Disable header text width contribution to automatic column width
532        const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth as i32;
533        /// Make the initial sort direction Ascending when first sorting on this column
534        const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending as i32;
535        /// Make the initial sort direction Descending when first sorting on this column
536        const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending as i32;
537        /// Display an angled header for this column (when angled headers feature is enabled)
538        const ANGLED_HEADER = sys::ImGuiTableColumnFlags_AngledHeader as i32;
539    }
540}
541
542/// Single-choice width mode for a table column.
543#[derive(Clone, Copy, Debug, PartialEq)]
544pub enum TableColumnWidth {
545    /// Initial value is interpreted as a fixed width in pixels.
546    Fixed(f32),
547    /// Initial value is interpreted as a stretch weight.
548    Stretch(f32),
549}
550
551impl TableColumnWidth {
552    pub const fn fixed(width: f32) -> Self {
553        Self::Fixed(width)
554    }
555
556    pub const fn stretch(weight: f32) -> Self {
557        Self::Stretch(weight)
558    }
559
560    #[inline]
561    pub(crate) const fn raw_flags(self) -> i32 {
562        match self {
563            Self::Fixed(_) => sys::ImGuiTableColumnFlags_WidthFixed as i32,
564            Self::Stretch(_) => sys::ImGuiTableColumnFlags_WidthStretch as i32,
565        }
566    }
567
568    #[inline]
569    pub(crate) const fn value(self) -> f32 {
570        match self {
571            Self::Fixed(value) | Self::Stretch(value) => value,
572        }
573    }
574}
575
576/// Single-choice indentation policy for a table column.
577#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
578pub enum TableColumnIndent {
579    /// Use the current indent value when entering the column.
580    Enable,
581    /// Disable indentation for the column.
582    Disable,
583}
584
585impl TableColumnIndent {
586    #[inline]
587    pub const fn bits(self) -> i32 {
588        self.raw_flags()
589    }
590
591    #[inline]
592    pub(crate) const fn raw_flags(self) -> i32 {
593        match self {
594            Self::Enable => sys::ImGuiTableColumnFlags_IndentEnable as i32,
595            Self::Disable => sys::ImGuiTableColumnFlags_IndentDisable as i32,
596        }
597    }
598}
599
600bitflags::bitflags! {
601    /// Flags returned by `TableGetColumnFlags()`.
602    #[repr(transparent)]
603    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
604    pub struct TableColumnStateFlags: i32 {
605        /// No flags
606        const NONE = 0;
607        /// Overriding/master disable flag: hide column and omit it from the context menu.
608        const DISABLED = sys::ImGuiTableColumnFlags_Disabled as i32;
609        /// Default to a hidden/disabled column.
610        const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide as i32;
611        /// Default to a sorting column.
612        const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort as i32;
613        /// Overriding width becomes fixed width
614        const WIDTH_FIXED = sys::ImGuiTableColumnFlags_WidthFixed as i32;
615        /// Overriding width becomes weight
616        const WIDTH_STRETCH = sys::ImGuiTableColumnFlags_WidthStretch as i32;
617        /// Disable manual resizing
618        const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize as i32;
619        /// Disable manual reordering this column
620        const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder as i32;
621        /// Disable ability to hide/disable this column
622        const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide as i32;
623        /// Disable clipping for this column
624        const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip as i32;
625        /// Disable ability to sort on this field
626        const NO_SORT = sys::ImGuiTableColumnFlags_NoSort as i32;
627        /// Disable ability to sort in the ascending direction
628        const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending as i32;
629        /// Disable ability to sort in the descending direction
630        const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending as i32;
631        /// TableHeadersRow() will not submit label for this column
632        const NO_HEADER_LABEL = sys::ImGuiTableColumnFlags_NoHeaderLabel as i32;
633        /// Disable header text width contribution to automatic column width
634        const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth as i32;
635        /// Make the initial sort direction Ascending when first sorting on this column
636        const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending as i32;
637        /// Make the initial sort direction Descending when first sorting on this column
638        const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending as i32;
639        /// Use current Indent value when entering cell
640        const INDENT_ENABLE = sys::ImGuiTableColumnFlags_IndentEnable as i32;
641        /// Disable indenting for this column
642        const INDENT_DISABLE = sys::ImGuiTableColumnFlags_IndentDisable as i32;
643        /// Display an angled header for this column (when angled headers feature is enabled)
644        const ANGLED_HEADER = sys::ImGuiTableColumnFlags_AngledHeader as i32;
645        /// Status: is enabled == not hidden
646        const IS_ENABLED = sys::ImGuiTableColumnFlags_IsEnabled as i32;
647        /// Status: is visible == is enabled AND not clipped by scrolling
648        const IS_VISIBLE = sys::ImGuiTableColumnFlags_IsVisible as i32;
649        /// Status: is currently part of the sort specs
650        const IS_SORTED = sys::ImGuiTableColumnFlags_IsSorted as i32;
651        /// Status: is hovered by mouse
652        const IS_HOVERED = sys::ImGuiTableColumnFlags_IsHovered as i32;
653    }
654}
655
656impl From<TableColumnFlags> for TableColumnStateFlags {
657    fn from(flags: TableColumnFlags) -> Self {
658        Self::from_bits_retain(flags.bits())
659    }
660}
661
662impl TableColumnFlags {
663    #[inline]
664    pub(crate) fn validate_for_setup(
665        self,
666        caller: &str,
667        width: Option<TableColumnWidth>,
668        indent: Option<TableColumnIndent>,
669    ) {
670        let unsupported_flags = self.bits() & !TableColumnFlags::all().bits();
671        assert!(
672            unsupported_flags == 0,
673            "{caller} received non-independent ImGuiTableColumnFlags bits: 0x{unsupported_flags:X}"
674        );
675        let bits = self.bits()
676            | width.map_or(0, TableColumnWidth::raw_flags)
677            | indent.map_or(0, TableColumnIndent::raw_flags);
678        let width_mask = sys::ImGuiTableColumnFlags_WidthMask_ as i32;
679        let indent_mask = sys::ImGuiTableColumnFlags_IndentMask_ as i32;
680        let supported = TableColumnFlags::all().bits() | width_mask | indent_mask;
681        let unsupported = bits & !supported;
682        assert!(
683            unsupported == 0,
684            "{caller} received unsupported ImGuiTableColumnFlags bits: 0x{unsupported:X}"
685        );
686        assert!(
687            (bits & width_mask).count_ones() <= 1,
688            "{caller} accepts at most one table column width policy"
689        );
690        assert!(
691            (bits & indent_mask).count_ones() <= 1,
692            "{caller} accepts at most one table column indent policy"
693        );
694    }
695}
696
697#[cfg(feature = "serde")]
698impl Serialize for TableColumnFlags {
699    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
700    where
701        S: serde::Serializer,
702    {
703        serializer.serialize_i32(self.bits())
704    }
705}
706
707#[cfg(feature = "serde")]
708impl<'de> Deserialize<'de> for TableColumnFlags {
709    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
710    where
711        D: serde::Deserializer<'de>,
712    {
713        let bits = i32::deserialize(deserializer)?;
714        Ok(TableColumnFlags::from_bits_truncate(bits))
715    }
716}
717
718#[cfg(feature = "serde")]
719impl Serialize for TableColumnStateFlags {
720    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
721    where
722        S: serde::Serializer,
723    {
724        serializer.serialize_i32(self.bits())
725    }
726}
727
728#[cfg(feature = "serde")]
729impl<'de> Deserialize<'de> for TableColumnStateFlags {
730    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
731    where
732        D: serde::Deserializer<'de>,
733    {
734        let bits = i32::deserialize(deserializer)?;
735        Ok(TableColumnStateFlags::from_bits_truncate(bits))
736    }
737}