1use super::*;
2
3impl<A> Ui<A> {
4 pub fn set_next_item_selection_user_data(&self, i: usize) {
5 unsafe {
6 ImGui_SetNextItemSelectionUserData(i as ImGuiSelectionUserData);
7 }
8 }
9 pub fn is_item_toggled_selection(&self) -> bool {
10 unsafe { ImGui_IsItemToggledSelection() }
11 }
12 pub fn with_multi_select<R, Storage: MultiSelectStorage>(
16 &self,
17 flags: MultiSelectFlags,
18 items_count: Option<usize>,
19 mut storage: Storage,
20 f: impl FnOnce(&mut Storage, &mut MultiSelect) -> R,
21 ) -> R {
22 let selection_size = storage
23 .size()
24 .and_then(|x| i32::try_from(x).ok())
25 .unwrap_or(-1);
26 let items_count = items_count
27 .and_then(|x| i32::try_from(x).ok())
28 .unwrap_or(-1);
29
30 let ms = unsafe { ImGui_BeginMultiSelect(flags.bits(), selection_size, items_count) };
31 let mut ms = MultiSelect(ms);
32 storage.apply_requests(&mut ms);
33
34 let res = f(&mut storage, &mut ms);
35
36 let ms = unsafe { ImGui_EndMultiSelect() };
37 let mut ms = MultiSelect(ms);
38 storage.apply_requests(&mut ms);
39
40 res
41 }
42}
43
44pub struct MultiSelect(*mut ImGuiMultiSelectIO);
45
46impl MultiSelect {
47 pub fn range_src_item(&self) -> usize {
48 unsafe { (*self.0).RangeSrcItem as usize }
49 }
50 pub fn nav_id_item(&self) -> usize {
51 unsafe { (*self.0).NavIdItem as usize }
52 }
53 pub fn nav_id_selected(&self) -> bool {
54 unsafe { (*self.0).NavIdSelected }
55 }
56 pub fn items_count(&self) -> usize {
57 unsafe { (*self.0).ItemsCount as usize }
58 }
59 pub fn set_range_src_reset(&mut self) {
60 unsafe {
61 (*self.0).RangeSrcReset = true;
62 }
63 }
64 pub fn iter(&self) -> impl Iterator<Item = SelectionRequest<'_>> {
65 unsafe { (*self.0).Requests.iter().map(SelectionRequest) }
66 }
67}
68
69pub struct SelectionRequest<'a>(&'a ImGuiSelectionRequest);
70
71impl SelectionRequest<'_> {
72 pub fn request_type(&self) -> SelectionRequestType {
73 SelectionRequestType::from_bits(self.0.Type).unwrap()
74 }
75 pub fn selected(&self) -> bool {
76 self.0.Selected
77 }
78 pub fn range_direction(&self) -> i8 {
79 self.0.RangeDirection
80 }
81 pub fn range_first_item(&self) -> usize {
82 self.0.RangeFirstItem as usize
83 }
84 pub fn range_last_item(&self) -> usize {
85 self.0.RangeLastItem as usize
86 }
87}
88
89pub trait MultiSelectStorage {
96 fn size(&self) -> Option<usize>;
97 fn apply_requests(&mut self, ms: &mut MultiSelect);
98}
99
100impl<T: MultiSelectStorage> MultiSelectStorage for &mut T {
102 fn size(&self) -> Option<usize> {
103 T::size(self)
104 }
105 fn apply_requests(&mut self, ms: &mut MultiSelect) {
106 T::apply_requests(self, ms)
107 }
108}
109
110type BoxFnIdxToID<'a> = Box<dyn FnMut(usize) -> ImGuiID + 'a>;
113
114extern "C" fn default_adapter_index_to_storage_id(
115 _: *mut ImGuiSelectionBasicStorage,
116 idx: i32,
117) -> ImGuiID {
118 idx as ImGuiID
119}
120
121extern "C" fn adapter_index_to_storage_id(
122 this: *mut ImGuiSelectionBasicStorage,
123 idx: i32,
124) -> ImGuiID {
125 unsafe {
126 let f = (*this).UserData as *mut BoxFnIdxToID;
127 if f.is_null() { 0 } else { (*f)(idx as usize) }
128 }
129}
130
131pub struct SelectionBasicStorage {
136 inner: ImGuiSelectionBasicStorage,
137}
138
139impl SelectionBasicStorage {
140 pub fn new() -> Self {
144 let mut inner = unsafe { ImGuiSelectionBasicStorage::new() };
145 inner.AdapterIndexToStorageId = Some(default_adapter_index_to_storage_id);
146 SelectionBasicStorage { inner }
147 }
148 pub fn with_callback_id<'a>(
153 &'a mut self,
154 f: impl FnMut(usize) -> ImGuiID + 'a,
155 ) -> SelectionBasicStorageWithCallback<'a> {
156 let f: BoxFnIdxToID<'a> = Box::new(f);
157 let f = Box::new(f);
158 self.inner.AdapterIndexToStorageId = Some(adapter_index_to_storage_id);
159 SelectionBasicStorageWithCallback {
160 inner: self,
161 boxed_f: f,
162 }
163 }
164 pub fn set_preserve_order(&mut self, preserve_order: bool) {
165 self.inner.PreserveOrder = preserve_order;
166 }
167 pub fn contains(&self, id: ImGuiID) -> bool {
168 unsafe { self.inner.Contains(id) }
169 }
170 pub fn clear(&mut self) {
171 unsafe {
172 self.inner.Clear();
173 }
174 }
175 pub fn set_item_selected(&mut self, id: ImGuiID, selected: bool) {
176 unsafe {
177 self.inner.SetItemSelected(id, selected);
178 }
179 }
180 pub fn swap(&mut self, other: &mut SelectionBasicStorage) {
181 unsafe {
182 self.inner.Swap(&mut other.inner);
183 }
184 }
185 pub fn iter(&self) -> SelectionBasicStorageIter<'_> {
186 SelectionBasicStorageIter {
187 inner: self,
188 ptr: std::ptr::null_mut(),
189 }
190 }
191}
192
193impl<'a> IntoIterator for &'a SelectionBasicStorage {
194 type Item = ImGuiID;
195 type IntoIter = SelectionBasicStorageIter<'a>;
196 fn into_iter(self) -> SelectionBasicStorageIter<'a> {
197 self.iter()
198 }
199}
200
201pub struct SelectionBasicStorageIter<'a> {
202 inner: &'a SelectionBasicStorage,
203 ptr: *mut c_void,
204}
205
206impl Iterator for SelectionBasicStorageIter<'_> {
207 type Item = ImGuiID;
208 fn next(&mut self) -> Option<ImGuiID> {
209 unsafe {
210 let mut id = 0;
211 let this = &self.inner.inner as *const _ as *mut _;
214 if ImGuiSelectionBasicStorage_GetNextSelectedItem(this, &mut self.ptr, &mut id) {
215 Some(id)
216 } else {
217 None
218 }
219 }
220 }
221}
222
223impl Default for SelectionBasicStorage {
224 fn default() -> Self {
225 Self::new()
226 }
227}
228
229impl MultiSelectStorage for SelectionBasicStorage {
230 fn size(&self) -> Option<usize> {
231 Some(self.inner.Size as usize)
232 }
233 fn apply_requests(&mut self, ms: &mut MultiSelect) {
234 unsafe {
235 self.inner.ApplyRequests(ms.0);
236 }
237 }
238}
239
240pub struct SelectionBasicStorageWithCallback<'a> {
241 inner: &'a mut SelectionBasicStorage,
242 boxed_f: BoxFnIdxToID<'a>,
243}
244
245impl SelectionBasicStorageWithCallback<'_> {
246 pub fn inner(&mut self) -> &mut SelectionBasicStorage {
248 self.inner
249 }
250 pub fn contains(&self, id: ImGuiID) -> bool {
254 self.inner.contains(id)
255 }
256}
257
258impl Drop for SelectionBasicStorageWithCallback<'_> {
259 fn drop(&mut self) {
260 self.inner.inner.UserData = std::ptr::null_mut();
262 self.inner.inner.AdapterIndexToStorageId = Some(default_adapter_index_to_storage_id);
263 }
264}
265
266impl<'a> MultiSelectStorage for SelectionBasicStorageWithCallback<'a> {
267 fn size(&self) -> Option<usize> {
268 self.inner.size()
269 }
270 fn apply_requests(&mut self, ms: &mut MultiSelect) {
271 self.inner.inner.UserData = &mut self.boxed_f as *mut BoxFnIdxToID<'a> as *mut c_void;
272 self.inner.apply_requests(ms);
273 }
274}
275
276type BoxFnExtSetter<'f, Storage> = Box<dyn FnMut(&mut Storage, usize, bool) + 'f>;
279type StorageAndSet<'f, Storage> = (Storage, BoxFnExtSetter<'f, Storage>);
280
281pub struct SelectionExternalStorage<'f, Storage> {
287 inner: ImGuiSelectionExternalStorage,
288 #[allow(clippy::type_complexity)]
289 selection_size: Box<dyn Fn(&Storage) -> Option<usize> + 'f>,
290 storage: StorageAndSet<'f, Storage>,
291}
292
293extern "C" fn adapter_set_item_selected<Storage>(
294 this: *mut ImGuiSelectionExternalStorage,
295 idx: i32,
296 selected: bool,
297) {
298 unsafe {
299 let storage_and_set = (*this).UserData as *mut StorageAndSet<'_, Storage>;
300 let (storage, setter) = &mut *storage_and_set;
301 setter(storage, idx as usize, selected);
302 }
303}
304
305impl<'f, Storage> SelectionExternalStorage<'f, Storage> {
306 pub fn new(
315 storage: Storage,
316 selection_size: impl Fn(&Storage) -> Option<usize> + 'f,
317 setter: impl FnMut(&mut Storage, usize, bool) + 'f,
318 ) -> Self {
319 let mut inner = unsafe { ImGuiSelectionExternalStorage::new() };
320 let setter: BoxFnExtSetter<'f, Storage> = Box::new(setter);
321 let storage = (storage, setter);
322 inner.AdapterSetItemSelected = Some(adapter_set_item_selected::<Storage>);
323 SelectionExternalStorage {
324 inner,
325 selection_size: Box::new(selection_size),
326 storage,
327 }
328 }
329 pub fn storage(&mut self) -> &mut Storage {
331 &mut self.storage.0
332 }
333 pub fn into_storage(self) -> Storage {
335 self.storage.0
336 }
337}
338
339impl<'f, Storage> MultiSelectStorage for SelectionExternalStorage<'f, Storage> {
340 fn size(&self) -> Option<usize> {
341 (self.selection_size)(&self.storage.0)
342 }
343 fn apply_requests(&mut self, ms: &mut MultiSelect) {
344 self.inner.UserData = &mut self.storage as *mut StorageAndSet<'f, Storage> as *mut c_void;
345 unsafe {
346 self.inner.ApplyRequests(ms.0);
347 }
348 }
349}