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 pub fn begin(self, ui: &Ui) -> Option<ListBoxToken<'_>> {
62 assert_finite_vec2("ListBox::begin()", "size", self.size);
63 let size_vec = sys::ImVec2 {
64 x: self.size[0],
65 y: self.size[1],
66 };
67 let should_render = unsafe { sys::igBeginListBox(ui.scratch_txt(self.label), size_vec) };
68 if should_render {
69 Some(ListBoxToken::new(ui))
70 } else {
71 None
72 }
73 }
74 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui, f: F) -> Option<R> {
79 self.begin(ui).map(|_list| f())
80 }
81}
82
83pub struct ListBoxToken<'ui> {
86 _ui: &'ui Ui,
87}
88
89impl<'ui> ListBoxToken<'ui> {
90 pub fn new(ui: &'ui Ui) -> Self {
92 Self { _ui: ui }
93 }
94
95 pub fn end(self) {
97 }
99}
100
101impl<'ui> Drop for ListBoxToken<'ui> {
102 fn drop(&mut self) {
103 unsafe {
104 sys::igEndListBox();
105 }
106 }
107}
108
109impl<T: AsRef<str>> ListBox<T> {
111 pub fn build_simple<V, L>(
113 self,
114 ui: &Ui,
115 current_item: &mut usize,
116 items: &[V],
117 label_fn: &L,
118 ) -> bool
119 where
120 for<'b> L: Fn(&'b V) -> Cow<'b, str>,
121 {
122 let mut result = false;
123 let lb = self;
124 if let Some(_cb) = lb.begin(ui) {
125 for (idx, item) in items.iter().enumerate() {
126 let text = label_fn(item);
127 let selected = idx == *current_item;
128 if ui.selectable_config(&text).selected(selected).build() {
129 *current_item = idx;
130 result = true;
131 }
132 }
133 }
134 result
135 }
136
137 pub fn build_simple_i32<V, L>(
142 self,
143 ui: &Ui,
144 current_item: &mut i32,
145 items: &[V],
146 label_fn: &L,
147 ) -> bool
148 where
149 for<'b> L: Fn(&'b V) -> Cow<'b, str>,
150 {
151 let mut result = false;
152 let lb = self;
153 if let Some(_cb) = lb.begin(ui) {
154 for (idx, item) in items.iter().enumerate() {
155 if idx > i32::MAX as usize {
156 break;
157 }
158 let idx_i32 = idx as i32;
159 let text = label_fn(item);
160 let selected = idx_i32 == *current_item;
161 if ui.selectable_config(&text).selected(selected).build() {
162 *current_item = idx_i32;
163 result = true;
164 }
165 }
166 }
167 result
168 }
169}