dear_imgui_rs/widget/
list_box.rs1use std::borrow::Cow;
6
7use crate::Ui;
8use crate::sys;
9
10fn assert_finite_vec2(caller: &str, name: &str, value: [f32; 2]) {
11 assert!(
12 value[0].is_finite() && value[1].is_finite(),
13 "{caller} {name} must contain finite values"
14 );
15}
16
17impl Ui {
19 pub fn list_box_config<T: AsRef<str>>(&self, label: T) -> ListBox<T> {
21 ListBox::new(label)
22 }
23}
24
25#[derive(Clone, Debug)]
27#[must_use]
28pub struct ListBox<T> {
29 label: T,
30 size: [f32; 2],
31}
32
33impl<T: AsRef<str>> ListBox<T> {
34 #[doc(alias = "ListBoxHeaderVec2", alias = "ListBoxHeaderInt")]
36 pub fn new(label: T) -> ListBox<T> {
37 ListBox {
38 label,
39 size: [0.0, 0.0],
40 }
41 }
42
43 #[inline]
50 pub fn size(mut self, size: impl Into<[f32; 2]>) -> Self {
51 self.size = size.into();
52 self
53 }
54 #[must_use]
61 #[doc(alias = "BeginListBox", alias = "ListBox")]
62 pub fn begin(self, ui: &Ui) -> Option<ListBoxToken<'_>> {
63 assert_finite_vec2("ListBox::begin()", "size", self.size);
64 let size_vec = sys::ImVec2 {
65 x: self.size[0],
66 y: self.size[1],
67 };
68 let label_ptr = ui.scratch_txt(self.label);
69 let should_render =
70 ui.run_with_bound_context(|| unsafe { sys::igBeginListBox(label_ptr, size_vec) });
71 if should_render {
72 Some(ListBoxToken::new(ui))
73 } else {
74 None
75 }
76 }
77 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
82 let token = self.begin(ui)?;
83 let result = f();
84 drop(token);
85 Some(result)
86 }
87}
88
89#[must_use]
95#[doc(alias = "EndListBox")]
96pub struct ListBoxToken<'ui> {
97 scope: crate::scope::NativeScopeToken<'ui>,
98}
99
100impl<'ui> ListBoxToken<'ui> {
101 pub(crate) fn new(ui: &'ui Ui) -> Self {
103 Self {
104 scope: ui.begin_native_scope(crate::scope::NativeScopePop::EndListBox, "ListBoxToken"),
105 }
106 }
107
108 pub fn end(self) {
115 }
117}
118
119impl<'ui> Drop for ListBoxToken<'ui> {
120 fn drop(&mut self) {
121 self.scope.finish();
122 }
123}
124
125impl<T: AsRef<str>> ListBox<T> {
127 pub fn build_simple<V, L>(
129 self,
130 ui: &Ui,
131 current_item: &mut usize,
132 items: &[V],
133 label_fn: &L,
134 ) -> bool
135 where
136 for<'b> L: Fn(&'b V) -> Cow<'b, str>,
137 {
138 let mut result = false;
139 let lb = self;
140 if let Some(_cb) = lb.begin(ui) {
141 for (idx, item) in items.iter().enumerate() {
142 let text = label_fn(item);
143 let selected = idx == *current_item;
144 if ui.selectable_config(&text).selected(selected).build() {
145 *current_item = idx;
146 result = true;
147 }
148 }
149 }
150 result
151 }
152
153 pub fn build_simple_i32<V, L>(
158 self,
159 ui: &Ui,
160 current_item: &mut i32,
161 items: &[V],
162 label_fn: &L,
163 ) -> bool
164 where
165 for<'b> L: Fn(&'b V) -> Cow<'b, str>,
166 {
167 let mut result = false;
168 let lb = self;
169 if let Some(_cb) = lb.begin(ui) {
170 for (idx, item) in items.iter().enumerate() {
171 if idx > i32::MAX as usize {
172 break;
173 }
174 let idx_i32 = idx as i32;
175 let text = label_fn(item);
176 let selected = idx_i32 == *current_item;
177 if ui.selectable_config(&text).selected(selected).build() {
178 *current_item = idx_i32;
179 result = true;
180 }
181 }
182 }
183 result
184 }
185}