1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use crate::{Ui, sys};
use super::MultiSelectOptions;
use super::basic_selection::BasicSelection;
use super::requests::apply_multi_select_requests_basic;
use super::scope::MultiSelectScope;
use super::storage::MultiSelectIndexStorage;
impl Ui {
/// Low-level entry point: begin a multi-select scope and return a RAII wrapper.
///
/// This is the closest safe wrapper to the raw `BeginMultiSelect()` /
/// `EndMultiSelect()` pair. It does not drive any selection storage by
/// itself; use `begin_io()` / `end().io()` and the helper methods to
/// implement custom patterns.
pub fn begin_multi_select_raw(
&self,
flags: impl Into<MultiSelectOptions>,
selection_size: Option<i32>,
items_count: usize,
) -> MultiSelectScope<'_> {
MultiSelectScope::new(flags, selection_size, items_count)
}
/// Multi-select helper for index-based storage.
///
/// This wraps `BeginMultiSelect()` / `EndMultiSelect()` and applies
/// selection requests to an index-addressable selection container.
///
/// Typical usage:
///
/// ```no_run
/// # use dear_imgui_rs::*;
/// # let mut ctx = Context::create();
/// # let ui = ctx.frame();
/// let mut selected = vec![false; 128];
///
/// ui.multi_select_indexed(&mut selected, MultiSelectOptions::new(), |ui, idx, is_selected| {
/// ui.text(format!(
/// "{} {}",
/// if is_selected { "[x]" } else { "[ ]" },
/// idx
/// ));
/// });
/// ```
///
/// Notes:
/// - `storage.len()` defines `items_count`.
/// - This helper uses the "external storage" pattern where selection is
/// stored entirely on the application side.
/// - Per-item selection toggles can be queried via
/// [`Ui::is_item_toggled_selection`].
pub fn multi_select_indexed<S, F>(
&self,
storage: &mut S,
flags: impl Into<MultiSelectOptions>,
mut render_item: F,
) where
S: MultiSelectIndexStorage,
F: FnMut(&Ui, usize, bool),
{
let items_count = storage.len();
let selection_size_i32 = storage
.selected_count_hint()
.and_then(|n| i32::try_from(n).ok())
.unwrap_or(-1);
let mut scope = MultiSelectScope::new(flags, Some(selection_size_i32), items_count);
// Apply SetAll requests (if any) before submitting items.
scope.apply_begin_requests_indexed(storage);
// Submit items: for each index we set SelectionUserData and let user
// draw widgets, passing the current selection state as `is_selected`.
for idx in 0..items_count {
unsafe {
sys::igSetNextItemSelectionUserData(idx as sys::ImGuiSelectionUserData);
}
let is_selected = storage.is_selected(idx);
render_item(self, idx, is_selected);
}
// End scope and apply requests generated during item submission.
scope.end().apply_requests_indexed(storage);
}
/// Multi-select helper for index-based storage inside an active table.
///
/// This is a convenience wrapper over [`Ui::multi_select_indexed`] that
/// automatically advances table rows and starts each row at column 0.
///
/// It expects to be called between `BeginTable`/`EndTable`.
pub fn table_multi_select_indexed<S, F>(
&self,
storage: &mut S,
flags: impl Into<MultiSelectOptions>,
mut build_row: F,
) where
S: MultiSelectIndexStorage,
F: FnMut(&Ui, usize, bool),
{
let row_count = storage.len();
let selection_size_i32 = storage
.selected_count_hint()
.and_then(|n| i32::try_from(n).ok())
.unwrap_or(-1);
let mut scope = MultiSelectScope::new(flags, Some(selection_size_i32), row_count);
scope.apply_begin_requests_indexed(storage);
for row in 0..row_count {
unsafe {
sys::igSetNextItemSelectionUserData(row as sys::ImGuiSelectionUserData);
}
// Start a new table row and move to first column.
self.table_next_row();
self.table_next_column();
let is_selected = storage.is_selected(row);
build_row(self, row, is_selected);
}
scope.end().apply_requests_indexed(storage);
}
/// Multi-select helper using [`BasicSelection`] as underlying storage.
///
/// This variant is suitable when items are naturally identified by `ImGuiID`
/// (e.g. stable ids for rows or tree nodes).
///
/// - `items_count`: number of items in the scope.
/// - `id_at_index`: maps `[0, items_count)` to the corresponding item id.
/// - `render_item`: called once per index to emit widgets for that item.
pub fn multi_select_basic<G, F>(
&self,
selection: &mut BasicSelection,
flags: impl Into<MultiSelectOptions>,
items_count: usize,
mut id_at_index: G,
mut render_item: F,
) where
G: FnMut(usize) -> crate::Id,
F: FnMut(&Ui, usize, crate::Id, bool),
{
let selection_size_i32 = i32::try_from(selection.len()).unwrap_or(-1);
let scope = MultiSelectScope::new(flags, Some(selection_size_i32), items_count);
unsafe {
apply_multi_select_requests_basic(
scope.ms_io_begin,
selection,
items_count,
&mut id_at_index,
);
}
for idx in 0..items_count {
unsafe {
sys::igSetNextItemSelectionUserData(idx as sys::ImGuiSelectionUserData);
}
let id = id_at_index(idx);
let is_selected = selection.contains(id);
render_item(self, idx, id, is_selected);
}
scope
.end()
.apply_requests_basic(selection, &mut id_at_index);
}
}