Skip to main content

dear_imgui_rs/widget/multi_select/
scope.rs

1use crate::sys;
2
3use super::basic_selection::BasicSelection;
4use super::options::MultiSelectOptions;
5use super::requests::{apply_multi_select_requests_basic, apply_multi_select_requests_indexed};
6use super::storage::MultiSelectIndexStorage;
7
8fn usize_to_i32(name: &str, value: usize) -> i32 {
9    i32::try_from(value).unwrap_or_else(|_| panic!("{name} exceeded ImGui's i32 range"))
10}
11
12/// RAII wrapper around `BeginMultiSelect()` / `EndMultiSelect()` for advanced users.
13///
14/// This gives direct, but scoped, access to the underlying `ImGuiMultiSelectIO`
15/// struct. It does not perform any selection updates by itself; you are expected
16/// to call helper methods or use the raw IO to drive your own storage.
17pub struct MultiSelectScope<'ui> {
18    ui: &'ui crate::Ui,
19    pub(super) ms_io_begin: *mut sys::ImGuiMultiSelectIO,
20    items_count: i32,
21    ended: bool,
22}
23
24impl<'ui> MultiSelectScope<'ui> {
25    pub(super) fn new(
26        ui: &'ui crate::Ui,
27        flags: impl Into<MultiSelectOptions>,
28        selection_size: Option<i32>,
29        items_count: usize,
30    ) -> Self {
31        let options = flags.into();
32        let selection_size_i32 = selection_size.unwrap_or(-1);
33        let items_count_i32 = usize_to_i32("items_count", items_count);
34        let ms_io_begin = ui.run_with_bound_context(|| unsafe {
35            sys::igBeginMultiSelect(options.raw(), selection_size_i32, items_count_i32)
36        });
37        Self {
38            ui,
39            ms_io_begin,
40            items_count: items_count_i32,
41            ended: false,
42        }
43    }
44
45    /// Access the IO struct returned by `BeginMultiSelect()`.
46    pub fn begin_io(&self) -> &sys::ImGuiMultiSelectIO {
47        unsafe { &*self.ms_io_begin }
48    }
49
50    /// Mutable access to the IO struct returned by `BeginMultiSelect()`.
51    pub fn begin_io_mut(&mut self) -> &mut sys::ImGuiMultiSelectIO {
52        unsafe { &mut *self.ms_io_begin }
53    }
54
55    /// Apply selection requests from `BeginMultiSelect()` to index-based storage.
56    pub fn apply_begin_requests_indexed<S: MultiSelectIndexStorage>(&mut self, storage: &mut S) {
57        unsafe {
58            apply_multi_select_requests_indexed(self.ms_io_begin, storage);
59        }
60    }
61
62    /// Finalize the multi-select scope and return an IO view for the end state.
63    ///
64    /// This calls `EndMultiSelect()` and returns a `MultiSelectEnd` wrapper
65    /// that can be used to apply the final selection requests.
66    pub fn end(mut self) -> MultiSelectEnd<'ui> {
67        let ms_io_end = self
68            .ui
69            .run_with_bound_context(|| unsafe { sys::igEndMultiSelect() });
70        self.ended = true;
71        MultiSelectEnd {
72            ms_io_end,
73            items_count: self.items_count,
74            _marker: std::marker::PhantomData,
75        }
76    }
77}
78
79impl Drop for MultiSelectScope<'_> {
80    fn drop(&mut self) {
81        if !self.ended {
82            self.ui.run_with_bound_context(|| unsafe {
83                sys::igEndMultiSelect();
84            });
85            self.ended = true;
86        }
87    }
88}
89
90/// IO view returned after calling `EndMultiSelect()` via [`MultiSelectScope::end`].
91pub struct MultiSelectEnd<'ui> {
92    ms_io_end: *mut sys::ImGuiMultiSelectIO,
93    items_count: i32,
94    _marker: std::marker::PhantomData<&'ui crate::Ui>,
95}
96
97impl<'ui> MultiSelectEnd<'ui> {
98    /// Access the IO struct returned by `EndMultiSelect()`.
99    pub fn io(&self) -> &sys::ImGuiMultiSelectIO {
100        unsafe { &*self.ms_io_end }
101    }
102
103    /// Mutable access to the IO struct returned by `EndMultiSelect()`.
104    pub fn io_mut(&mut self) -> &mut sys::ImGuiMultiSelectIO {
105        unsafe { &mut *self.ms_io_end }
106    }
107
108    /// Apply selection requests from `EndMultiSelect()` to index-based storage.
109    pub fn apply_requests_indexed<S: MultiSelectIndexStorage>(&mut self, storage: &mut S) {
110        unsafe {
111            apply_multi_select_requests_indexed(self.ms_io_end, storage);
112        }
113    }
114
115    /// Apply selection requests from `EndMultiSelect()` to a [`BasicSelection`].
116    pub fn apply_requests_basic<G>(&mut self, selection: &mut BasicSelection, mut id_at_index: G)
117    where
118        G: FnMut(usize) -> crate::Id,
119    {
120        unsafe {
121            apply_multi_select_requests_basic(
122                self.ms_io_end,
123                selection,
124                self.items_count as usize,
125                &mut id_at_index,
126            );
127        }
128    }
129}