Skip to main content

dear_imgui_rs/widget/table/
indices.rs

1use crate::sys;
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5pub(crate) const TABLE_MAX_COLUMNS: usize = 512;
6
7/// Concrete zero-based table column index.
8///
9/// This represents a real table column only. Dear ImGui's `-1` current/default
10/// sentinel is represented by [`TableColumnRef::Current`] instead.
11#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13pub struct TableColumnIndex(usize);
14
15impl TableColumnIndex {
16    /// The first table column.
17    pub const ZERO: Self = Self(0);
18
19    /// Create a table column index from a Rust `usize`.
20    #[inline]
21    pub const fn new(index: usize) -> Self {
22        Self(index)
23    }
24
25    /// Return the zero-based Rust index.
26    #[inline]
27    pub const fn get(self) -> usize {
28        self.0
29    }
30
31    #[inline]
32    pub(crate) fn into_i32(self, caller: &str) -> i32 {
33        i32::try_from(self.0).unwrap_or_else(|_| {
34            panic!("{caller} column index exceeded Dear ImGui's i32 range");
35        })
36    }
37
38    #[inline]
39    pub(crate) fn into_imgui_column_idx(self, caller: &str) -> sys::ImGuiTableColumnIdx {
40        sys::ImGuiTableColumnIdx::try_from(self.0).unwrap_or_else(|_| {
41            panic!("{caller} column index exceeded Dear ImGui's ImGuiTableColumnIdx range");
42        })
43    }
44
45    #[inline]
46    pub(crate) fn from_imgui_column_idx(raw: sys::ImGuiTableColumnIdx, caller: &str) -> Self {
47        assert!(raw >= 0, "{caller} returned a negative table column index");
48        Self(
49            usize::try_from(raw)
50                .expect("non-negative Dear ImGui table column index must fit usize"),
51        )
52    }
53
54    #[inline]
55    pub(crate) fn from_i32(raw: i32, caller: &str) -> Self {
56        assert!(raw >= 0, "{caller} returned a negative table column index");
57        Self(usize::try_from(raw).expect("non-negative table column index must fit usize"))
58    }
59}
60
61impl From<usize> for TableColumnIndex {
62    #[inline]
63    fn from(index: usize) -> Self {
64        Self::new(index)
65    }
66}
67
68impl From<TableColumnIndex> for usize {
69    #[inline]
70    fn from(index: TableColumnIndex) -> Self {
71        index.get()
72    }
73}
74
75impl PartialEq<usize> for TableColumnIndex {
76    #[inline]
77    fn eq(&self, other: &usize) -> bool {
78        self.get() == *other
79    }
80}
81
82impl PartialEq<TableColumnIndex> for usize {
83    #[inline]
84    fn eq(&self, other: &TableColumnIndex) -> bool {
85        *self == other.get()
86    }
87}
88
89/// Table column selector for APIs that accept Dear ImGui's current-column sentinel.
90#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
91#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
92pub enum TableColumnRef {
93    /// Use the table's current column.
94    #[default]
95    Current,
96    /// Use a concrete table column index.
97    Index(TableColumnIndex),
98}
99
100impl TableColumnRef {
101    /// Current table column.
102    pub const CURRENT: Self = Self::Current;
103
104    /// Select a concrete table column.
105    #[inline]
106    pub const fn index(index: TableColumnIndex) -> Self {
107        Self::Index(index)
108    }
109}
110
111impl From<TableColumnIndex> for TableColumnRef {
112    #[inline]
113    fn from(index: TableColumnIndex) -> Self {
114        Self::Index(index)
115    }
116}
117
118impl From<usize> for TableColumnRef {
119    #[inline]
120    fn from(index: usize) -> Self {
121        Self::Index(TableColumnIndex::new(index))
122    }
123}
124
125/// Result of [`Ui::table_get_hovered_column`].
126#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128pub enum TableHoveredColumn {
129    /// The table is not hovered.
130    None,
131    /// A concrete table column is hovered.
132    Column(TableColumnIndex),
133    /// The unused space after the right-most visible column is hovered.
134    UnusedSpace,
135}
136
137/// Concrete zero-based table row index.
138#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
140pub struct TableRowIndex(usize);
141
142impl TableRowIndex {
143    /// The first table row.
144    pub const ZERO: Self = Self(0);
145
146    /// Create a table row index from a Rust `usize`.
147    #[inline]
148    pub const fn new(index: usize) -> Self {
149        Self(index)
150    }
151
152    /// Return the zero-based Rust index.
153    #[inline]
154    pub const fn get(self) -> usize {
155        self.0
156    }
157
158    #[inline]
159    pub(crate) fn from_i32(raw: i32, caller: &str) -> Self {
160        assert!(raw >= 0, "{caller} returned a negative table row index");
161        Self(usize::try_from(raw).expect("non-negative table row index must fit usize"))
162    }
163}
164
165impl From<usize> for TableRowIndex {
166    #[inline]
167    fn from(index: usize) -> Self {
168        Self::new(index)
169    }
170}
171
172impl From<TableRowIndex> for usize {
173    #[inline]
174    fn from(index: TableRowIndex) -> Self {
175        index.get()
176    }
177}
178
179impl PartialEq<usize> for TableRowIndex {
180    #[inline]
181    fn eq(&self, other: &usize) -> bool {
182        self.get() == *other
183    }
184}
185
186impl PartialEq<TableRowIndex> for usize {
187    #[inline]
188    fn eq(&self, other: &TableRowIndex) -> bool {
189        *self == other.get()
190    }
191}
192
193/// Result of [`Ui::table_get_hovered_row`].
194#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
195#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
196pub enum TableHoveredRow {
197    /// The table is not hovered.
198    None,
199    /// A table row index is hovered.
200    Row(TableRowIndex),
201}
202
203impl TableHoveredRow {
204    /// Return the hovered concrete row, if any.
205    #[inline]
206    pub const fn row(self) -> Option<TableRowIndex> {
207        match self {
208            Self::Row(index) => Some(index),
209            Self::None => None,
210        }
211    }
212}
213
214impl TableHoveredColumn {
215    /// Return the hovered concrete column, if any.
216    #[inline]
217    pub const fn column(self) -> Option<TableColumnIndex> {
218        match self {
219            Self::Column(index) => Some(index),
220            Self::None | Self::UnusedSpace => None,
221        }
222    }
223}
224
225/// Target column for opening a table context menu.
226#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
227#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
228pub enum TableContextMenuTarget {
229    /// Use Dear ImGui's default: current column when inside a column, otherwise table-level.
230    #[default]
231    CurrentColumn,
232    /// Open the context menu for a concrete column.
233    Column(TableColumnIndex),
234    /// Force a table-level context menu even when a column is current.
235    Table,
236}
237
238impl From<TableColumnIndex> for TableContextMenuTarget {
239    #[inline]
240    fn from(index: TableColumnIndex) -> Self {
241        Self::Column(index)
242    }
243}
244
245impl From<usize> for TableContextMenuTarget {
246    #[inline]
247    fn from(index: usize) -> Self {
248        Self::Column(TableColumnIndex::new(index))
249    }
250}