Skip to main content

dear_imgui_rs/widget/table/
options.rs

1use crate::sys;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5bitflags::bitflags! {
6    /// Independent flags for table widgets.
7    ///
8    /// The table sizing policy is a single-choice setting represented by
9    /// [`TableSizingPolicy`].
10    #[repr(transparent)]
11    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12    pub struct TableFlags: i32 {
13        /// No flags
14        const NONE = 0;
15        /// Enable resizing columns
16        const RESIZABLE = sys::ImGuiTableFlags_Resizable as i32;
17        /// Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
18        const REORDERABLE = sys::ImGuiTableFlags_Reorderable as i32;
19        /// Enable hiding/disabling columns in context menu
20        const HIDEABLE = sys::ImGuiTableFlags_Hideable as i32;
21        /// Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.
22        const SORTABLE = sys::ImGuiTableFlags_Sortable as i32;
23        /// Disable persisting columns order, width and sort settings in the .ini file
24        const NO_SAVED_SETTINGS = sys::ImGuiTableFlags_NoSavedSettings as i32;
25        /// Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
26        const CONTEXT_MENU_IN_BODY = sys::ImGuiTableFlags_ContextMenuInBody as i32;
27        /// Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
28        const ROW_BG = sys::ImGuiTableFlags_RowBg as i32;
29        /// Draw horizontal borders between rows
30        const BORDERS_INNER_H = sys::ImGuiTableFlags_BordersInnerH as i32;
31        /// Draw horizontal borders at the top and bottom
32        const BORDERS_OUTER_H = sys::ImGuiTableFlags_BordersOuterH as i32;
33        /// Draw vertical borders between columns
34        const BORDERS_INNER_V = sys::ImGuiTableFlags_BordersInnerV as i32;
35        /// Draw vertical borders on the left and right sides
36        const BORDERS_OUTER_V = sys::ImGuiTableFlags_BordersOuterV as i32;
37        /// Draw horizontal borders
38        const BORDERS_H = Self::BORDERS_INNER_H.bits() | Self::BORDERS_OUTER_H.bits();
39        /// Draw vertical borders
40        const BORDERS_V = Self::BORDERS_INNER_V.bits() | Self::BORDERS_OUTER_V.bits();
41        /// Draw inner borders
42        const BORDERS_INNER = Self::BORDERS_INNER_V.bits() | Self::BORDERS_INNER_H.bits();
43        /// Draw outer borders
44        const BORDERS_OUTER = Self::BORDERS_OUTER_V.bits() | Self::BORDERS_OUTER_H.bits();
45        /// Draw all borders
46        const BORDERS = Self::BORDERS_INNER.bits() | Self::BORDERS_OUTER.bits();
47        /// [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style
48        const NO_BORDERS_IN_BODY = sys::ImGuiTableFlags_NoBordersInBody as i32;
49        /// [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style
50        const NO_BORDERS_IN_BODY_UNTIL_RESIZE = sys::ImGuiTableFlags_NoBordersInBodyUntilResize as i32;
51        /// 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.
52        const NO_HOST_EXTEND_X = sys::ImGuiTableFlags_NoHostExtendX as i32;
53        /// 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.
54        const NO_HOST_EXTEND_Y = sys::ImGuiTableFlags_NoHostExtendY as i32;
55        /// Disable keeping column always minimally visible when ScrollX is on and table gets too small. Not recommended if columns are resizable.
56        const NO_KEEP_COLUMNS_VISIBLE = sys::ImGuiTableFlags_NoKeepColumnsVisible as i32;
57        /// 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.
58        const PRECISE_WIDTHS = sys::ImGuiTableFlags_PreciseWidths as i32;
59        /// Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().
60        const NO_CLIP = sys::ImGuiTableFlags_NoClip as i32;
61        /// Default if BordersOuterV is on. Enable outer-most padding. Generally desirable if you have headers.
62        const PAD_OUTER_X = sys::ImGuiTableFlags_PadOuterX as i32;
63        /// Default if BordersOuterV is off. Disable outer-most padding.
64        const NO_PAD_OUTER_X = sys::ImGuiTableFlags_NoPadOuterX as i32;
65        /// Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).
66        const NO_PAD_INNER_X = sys::ImGuiTableFlags_NoPadInnerX as i32;
67        /// 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.
68        const SCROLL_X = sys::ImGuiTableFlags_ScrollX as i32;
69        /// Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
70        const SCROLL_Y = sys::ImGuiTableFlags_ScrollY as i32;
71        /// Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
72        const SORT_MULTI = sys::ImGuiTableFlags_SortMulti as i32;
73        /// Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
74        const SORT_TRISTATE = sys::ImGuiTableFlags_SortTristate as i32;
75        /// Highlight column headers when hovered (may not be visible if table header is declaring a background color)
76        const HIGHLIGHT_HOVERED_COLUMN = sys::ImGuiTableFlags_HighlightHoveredColumn as i32;
77    }
78}
79
80/// Single-choice table sizing policy.
81#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
82pub enum TableSizingPolicy {
83    /// Columns default to fixed/auto widths matching contents width.
84    FixedFit,
85    /// Fixed/auto widths matching the maximum contents width of all columns.
86    FixedSame,
87    /// Stretch columns with weights proportional to contents widths.
88    StretchProp,
89    /// Stretch columns with equal weights unless overridden per column.
90    StretchSame,
91}
92
93impl TableSizingPolicy {
94    #[inline]
95    const fn raw(self) -> i32 {
96        match self {
97            Self::FixedFit => sys::ImGuiTableFlags_SizingFixedFit as i32,
98            Self::FixedSame => sys::ImGuiTableFlags_SizingFixedSame as i32,
99            Self::StretchProp => sys::ImGuiTableFlags_SizingStretchProp as i32,
100            Self::StretchSame => sys::ImGuiTableFlags_SizingStretchSame as i32,
101        }
102    }
103}
104
105/// Complete table options assembled from independent flags and an optional
106/// single sizing policy.
107#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
108pub struct TableOptions {
109    pub flags: TableFlags,
110    pub sizing_policy: Option<TableSizingPolicy>,
111}
112
113impl Default for TableOptions {
114    fn default() -> Self {
115        Self::new()
116    }
117}
118
119impl TableOptions {
120    pub const fn new() -> Self {
121        Self {
122            flags: TableFlags::NONE,
123            sizing_policy: None,
124        }
125    }
126
127    pub fn flags(mut self, flags: TableFlags) -> Self {
128        self.flags = flags;
129        self
130    }
131
132    pub fn sizing_policy(mut self, policy: TableSizingPolicy) -> Self {
133        self.sizing_policy = Some(policy);
134        self
135    }
136
137    pub fn bits(self) -> i32 {
138        self.raw()
139    }
140
141    #[inline]
142    pub(crate) fn raw(self) -> i32 {
143        self.flags.bits() | self.sizing_policy.map_or(0, TableSizingPolicy::raw)
144    }
145
146    #[inline]
147    pub(crate) fn validate(self, caller: &str) {
148        let unsupported_flags = self.flags.bits() & !TableFlags::all().bits();
149        assert!(
150            unsupported_flags == 0,
151            "{caller} received non-independent ImGuiTableFlags bits: 0x{unsupported_flags:X}"
152        );
153        let bits = self.raw();
154        let sizing_mask = sys::ImGuiTableFlags_SizingMask_ as i32;
155        let supported = TableFlags::all().bits() | sizing_mask;
156        let unsupported = bits & !supported;
157        assert!(
158            unsupported == 0,
159            "{caller} received unsupported ImGuiTableFlags bits: 0x{unsupported:X}"
160        );
161        let sizing_policy = bits & sizing_mask;
162        assert!(
163            is_valid_table_sizing_policy(sizing_policy),
164            "{caller} received invalid table sizing policy bits: 0x{sizing_policy:X}"
165        );
166    }
167}
168
169#[inline]
170const fn is_valid_table_sizing_policy(bits: i32) -> bool {
171    bits == 0
172        || bits == TableSizingPolicy::FixedFit.raw()
173        || bits == TableSizingPolicy::FixedSame.raw()
174        || bits == TableSizingPolicy::StretchProp.raw()
175        || bits == TableSizingPolicy::StretchSame.raw()
176}
177
178impl From<TableFlags> for TableOptions {
179    fn from(flags: TableFlags) -> Self {
180        Self::new().flags(flags)
181    }
182}
183
184#[cfg(feature = "serde")]
185impl Serialize for TableFlags {
186    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187    where
188        S: serde::Serializer,
189    {
190        serializer.serialize_i32(self.bits())
191    }
192}
193
194#[cfg(feature = "serde")]
195impl<'de> Deserialize<'de> for TableFlags {
196    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
197    where
198        D: serde::Deserializer<'de>,
199    {
200        let bits = i32::deserialize(deserializer)?;
201        Ok(TableFlags::from_bits_retain(bits))
202    }
203}
204
205bitflags::bitflags! {
206    /// Independent flags accepted by `TableSetupColumn()`.
207    ///
208    /// The fixed/stretch width mode and indent mode are single-choice settings
209    /// represented by [`TableColumnWidth`] and [`TableColumnIndent`].
210    #[repr(transparent)]
211    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
212    pub struct TableColumnFlags: i32 {
213        /// No flags
214        const NONE = 0;
215        /// Hide column and omit it from the context menu.
216        const DISABLED = sys::ImGuiTableColumnFlags_Disabled as i32;
217        /// Default to a hidden/disabled column.
218        const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide as i32;
219        /// Default to a sorting column.
220        const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort as i32;
221        /// Disable manual resizing
222        const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize as i32;
223        /// Disable manual reordering this column
224        const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder as i32;
225        /// Disable ability to hide/disable this column
226        const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide as i32;
227        /// Disable clipping for this column
228        const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip as i32;
229        /// Disable ability to sort on this field
230        const NO_SORT = sys::ImGuiTableColumnFlags_NoSort as i32;
231        /// Disable ability to sort in the ascending direction
232        const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending as i32;
233        /// Disable ability to sort in the descending direction
234        const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending as i32;
235        /// TableHeadersRow() will not submit label for this column
236        const NO_HEADER_LABEL = sys::ImGuiTableColumnFlags_NoHeaderLabel as i32;
237        /// Disable header text width contribution to automatic column width
238        const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth as i32;
239        /// Make the initial sort direction Ascending when first sorting on this column
240        const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending as i32;
241        /// Make the initial sort direction Descending when first sorting on this column
242        const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending as i32;
243        /// Display an angled header for this column (when angled headers feature is enabled)
244        const ANGLED_HEADER = sys::ImGuiTableColumnFlags_AngledHeader as i32;
245    }
246}
247
248/// Single-choice width mode for a table column.
249#[derive(Clone, Copy, Debug, PartialEq)]
250pub enum TableColumnWidth {
251    /// Initial value is interpreted as a fixed width in pixels.
252    Fixed(f32),
253    /// Initial value is interpreted as a stretch weight.
254    Stretch(f32),
255}
256
257impl TableColumnWidth {
258    pub const fn fixed(width: f32) -> Self {
259        Self::Fixed(width)
260    }
261
262    pub const fn stretch(weight: f32) -> Self {
263        Self::Stretch(weight)
264    }
265
266    #[inline]
267    pub(crate) const fn raw_flags(self) -> i32 {
268        match self {
269            Self::Fixed(_) => sys::ImGuiTableColumnFlags_WidthFixed as i32,
270            Self::Stretch(_) => sys::ImGuiTableColumnFlags_WidthStretch as i32,
271        }
272    }
273
274    #[inline]
275    pub(crate) const fn value(self) -> f32 {
276        match self {
277            Self::Fixed(value) | Self::Stretch(value) => value,
278        }
279    }
280}
281
282/// Single-choice indentation policy for a table column.
283#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
284pub enum TableColumnIndent {
285    /// Use the current indent value when entering the column.
286    Enable,
287    /// Disable indentation for the column.
288    Disable,
289}
290
291impl TableColumnIndent {
292    #[inline]
293    pub const fn bits(self) -> i32 {
294        self.raw_flags()
295    }
296
297    #[inline]
298    pub(crate) const fn raw_flags(self) -> i32 {
299        match self {
300            Self::Enable => sys::ImGuiTableColumnFlags_IndentEnable as i32,
301            Self::Disable => sys::ImGuiTableColumnFlags_IndentDisable as i32,
302        }
303    }
304}
305
306bitflags::bitflags! {
307    /// Flags returned by `TableGetColumnFlags()`.
308    #[repr(transparent)]
309    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
310    pub struct TableColumnStateFlags: i32 {
311        /// No flags
312        const NONE = 0;
313        /// Overriding/master disable flag: hide column and omit it from the context menu.
314        const DISABLED = sys::ImGuiTableColumnFlags_Disabled as i32;
315        /// Default to a hidden/disabled column.
316        const DEFAULT_HIDE = sys::ImGuiTableColumnFlags_DefaultHide as i32;
317        /// Default to a sorting column.
318        const DEFAULT_SORT = sys::ImGuiTableColumnFlags_DefaultSort as i32;
319        /// Overriding width becomes fixed width
320        const WIDTH_FIXED = sys::ImGuiTableColumnFlags_WidthFixed as i32;
321        /// Overriding width becomes weight
322        const WIDTH_STRETCH = sys::ImGuiTableColumnFlags_WidthStretch as i32;
323        /// Disable manual resizing
324        const NO_RESIZE = sys::ImGuiTableColumnFlags_NoResize as i32;
325        /// Disable manual reordering this column
326        const NO_REORDER = sys::ImGuiTableColumnFlags_NoReorder as i32;
327        /// Disable ability to hide/disable this column
328        const NO_HIDE = sys::ImGuiTableColumnFlags_NoHide as i32;
329        /// Disable clipping for this column
330        const NO_CLIP = sys::ImGuiTableColumnFlags_NoClip as i32;
331        /// Disable ability to sort on this field
332        const NO_SORT = sys::ImGuiTableColumnFlags_NoSort as i32;
333        /// Disable ability to sort in the ascending direction
334        const NO_SORT_ASCENDING = sys::ImGuiTableColumnFlags_NoSortAscending as i32;
335        /// Disable ability to sort in the descending direction
336        const NO_SORT_DESCENDING = sys::ImGuiTableColumnFlags_NoSortDescending as i32;
337        /// TableHeadersRow() will not submit label for this column
338        const NO_HEADER_LABEL = sys::ImGuiTableColumnFlags_NoHeaderLabel as i32;
339        /// Disable header text width contribution to automatic column width
340        const NO_HEADER_WIDTH = sys::ImGuiTableColumnFlags_NoHeaderWidth as i32;
341        /// Make the initial sort direction Ascending when first sorting on this column
342        const PREFER_SORT_ASCENDING = sys::ImGuiTableColumnFlags_PreferSortAscending as i32;
343        /// Make the initial sort direction Descending when first sorting on this column
344        const PREFER_SORT_DESCENDING = sys::ImGuiTableColumnFlags_PreferSortDescending as i32;
345        /// Use current Indent value when entering cell
346        const INDENT_ENABLE = sys::ImGuiTableColumnFlags_IndentEnable as i32;
347        /// Disable indenting for this column
348        const INDENT_DISABLE = sys::ImGuiTableColumnFlags_IndentDisable as i32;
349        /// Display an angled header for this column (when angled headers feature is enabled)
350        const ANGLED_HEADER = sys::ImGuiTableColumnFlags_AngledHeader as i32;
351        /// Status: is enabled == not hidden
352        const IS_ENABLED = sys::ImGuiTableColumnFlags_IsEnabled as i32;
353        /// Status: is visible == is enabled AND not clipped by scrolling
354        const IS_VISIBLE = sys::ImGuiTableColumnFlags_IsVisible as i32;
355        /// Status: is currently part of the sort specs
356        const IS_SORTED = sys::ImGuiTableColumnFlags_IsSorted as i32;
357        /// Status: is hovered by mouse
358        const IS_HOVERED = sys::ImGuiTableColumnFlags_IsHovered as i32;
359    }
360}
361
362impl From<TableColumnFlags> for TableColumnStateFlags {
363    fn from(flags: TableColumnFlags) -> Self {
364        Self::from_bits_retain(flags.bits())
365    }
366}
367
368impl TableColumnFlags {
369    #[inline]
370    pub(crate) fn validate_for_setup(
371        self,
372        caller: &str,
373        width: Option<TableColumnWidth>,
374        indent: Option<TableColumnIndent>,
375    ) {
376        let unsupported_flags = self.bits() & !TableColumnFlags::all().bits();
377        assert!(
378            unsupported_flags == 0,
379            "{caller} received non-independent ImGuiTableColumnFlags bits: 0x{unsupported_flags:X}"
380        );
381        let bits = self.bits()
382            | width.map_or(0, TableColumnWidth::raw_flags)
383            | indent.map_or(0, TableColumnIndent::raw_flags);
384        let width_mask = sys::ImGuiTableColumnFlags_WidthMask_ as i32;
385        let indent_mask = sys::ImGuiTableColumnFlags_IndentMask_ as i32;
386        let supported = TableColumnFlags::all().bits() | width_mask | indent_mask;
387        let unsupported = bits & !supported;
388        assert!(
389            unsupported == 0,
390            "{caller} received unsupported ImGuiTableColumnFlags bits: 0x{unsupported:X}"
391        );
392        assert!(
393            (bits & width_mask).count_ones() <= 1,
394            "{caller} accepts at most one table column width policy"
395        );
396        assert!(
397            (bits & indent_mask).count_ones() <= 1,
398            "{caller} accepts at most one table column indent policy"
399        );
400    }
401}
402
403#[cfg(feature = "serde")]
404impl Serialize for TableColumnFlags {
405    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
406    where
407        S: serde::Serializer,
408    {
409        serializer.serialize_i32(self.bits())
410    }
411}
412
413#[cfg(feature = "serde")]
414impl<'de> Deserialize<'de> for TableColumnFlags {
415    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
416    where
417        D: serde::Deserializer<'de>,
418    {
419        let bits = i32::deserialize(deserializer)?;
420        Ok(TableColumnFlags::from_bits_retain(bits))
421    }
422}
423
424#[cfg(feature = "serde")]
425impl Serialize for TableColumnStateFlags {
426    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
427    where
428        S: serde::Serializer,
429    {
430        serializer.serialize_i32(self.bits())
431    }
432}
433
434#[cfg(feature = "serde")]
435impl<'de> Deserialize<'de> for TableColumnStateFlags {
436    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
437    where
438        D: serde::Deserializer<'de>,
439    {
440        let bits = i32::deserialize(deserializer)?;
441        Ok(TableColumnStateFlags::from_bits_retain(bits))
442    }
443}