dear_imgui_rs/widget/table/
sort.rs1use crate::sys;
2use crate::ui::Ui;
3use crate::widget::table::{TableColumnIndex, TableColumnUserData};
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7#[repr(u8)]
9#[derive(Copy, Clone, Debug, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub enum SortDirection {
12 None = sys::ImGuiSortDirection_None as u8,
13 Ascending = sys::ImGuiSortDirection_Ascending as u8,
14 Descending = sys::ImGuiSortDirection_Descending as u8,
15}
16
17impl From<SortDirection> for sys::ImGuiSortDirection {
18 #[inline]
19 fn from(value: SortDirection) -> sys::ImGuiSortDirection {
20 match value {
21 SortDirection::None => sys::ImGuiSortDirection_None,
22 SortDirection::Ascending => sys::ImGuiSortDirection_Ascending,
23 SortDirection::Descending => sys::ImGuiSortDirection_Descending,
24 }
25 }
26}
27
28#[derive(Copy, Clone, Debug, PartialEq, Eq)]
30pub struct TableColumnSortSpec {
31 pub column_user_data: TableColumnUserData,
32 pub column_index: TableColumnIndex,
33 pub sort_order: i16,
34 pub sort_direction: SortDirection,
35}
36
37#[derive(Debug)]
43pub struct TableSortSpecs {
44 specs: Box<[TableColumnSortSpec]>,
45 dirty: bool,
46 source_context: *mut sys::ImGuiContext,
47 source_scope: crate::scope::TableScope,
48}
49
50impl TableSortSpecs {
51 pub(crate) unsafe fn from_raw(
54 ui: &Ui,
55 table: *mut sys::ImGuiTable,
56 raw: *mut sys::ImGuiTableSortSpecs,
57 ) -> Self {
58 debug_assert_eq!(unsafe { sys::igGetCurrentTable() }, table);
59 let (dirty, specs) = unsafe { copy_table_sort_specs(raw) };
60 let source_scope = ui
61 .current_native_scope()
62 .table()
63 .expect("TableSortSpecs::from_raw() requires a current table");
64 Self {
65 specs,
66 dirty,
67 source_context: ui.context_raw(),
68 source_scope,
69 }
70 }
71
72 pub fn is_dirty(&self) -> bool {
74 self.dirty
75 }
76
77 pub fn clear_dirty(&mut self, ui: &Ui) {
85 if !self.dirty {
86 return;
87 }
88 assert!(
89 std::ptr::eq(ui.context_raw(), self.source_context),
90 "TableSortSpecs::clear_dirty() requires the Ui that produced this snapshot"
91 );
92 ui.run_with_bound_context(|| unsafe {
93 assert_eq!(
94 ui.current_native_scope().table(),
95 Some(self.source_scope),
96 "TableSortSpecs::clear_dirty() source table is no longer current"
97 );
98 let raw = sys::igTableGetSortSpecs();
99 assert!(
100 !raw.is_null(),
101 "TableSortSpecs::clear_dirty() current table has no sort specifications"
102 );
103 (*raw).SpecsDirty = false;
104 });
105 self.dirty = false;
106 }
107
108 pub fn len(&self) -> usize {
110 self.specs.len()
111 }
112
113 pub fn is_empty(&self) -> bool {
114 self.len() == 0
115 }
116
117 pub fn iter(&self) -> std::slice::Iter<'_, TableColumnSortSpec> {
119 self.specs.iter()
120 }
121}
122
123pub(super) unsafe fn copy_table_sort_specs(
124 raw: *mut sys::ImGuiTableSortSpecs,
125) -> (bool, Box<[TableColumnSortSpec]>) {
126 assert!(!raw.is_null(), "table sort specs pointer must not be null");
127 let count = usize::try_from(unsafe { (*raw).SpecsCount })
128 .expect("Dear ImGui returned a negative table sort specification count");
129 let source = unsafe { (*raw).Specs };
130 assert!(
131 count == 0 || !source.is_null(),
132 "Dear ImGui returned null table sort specification data for a non-empty snapshot"
133 );
134 let mut specs = Vec::with_capacity(count);
135 for index in 0..count {
136 let spec = unsafe { &*source.add(index) };
137 let direction = match spec.SortDirection as u8 {
138 value if value == sys::ImGuiSortDirection_Ascending as u8 => SortDirection::Ascending,
139 value if value == sys::ImGuiSortDirection_Descending as u8 => SortDirection::Descending,
140 _ => SortDirection::None,
141 };
142 specs.push(TableColumnSortSpec {
143 column_user_data: TableColumnUserData::new(spec.ColumnUserID),
144 column_index: TableColumnIndex::from_imgui_column_idx(
145 spec.ColumnIndex,
146 "TableSortSpecs::from_raw()",
147 ),
148 sort_order: spec.SortOrder,
149 sort_direction: direction,
150 });
151 }
152 (unsafe { (*raw).SpecsDirty }, specs.into_boxed_slice())
153}