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
use std::borrow::Cow;
use crate::imgui::string::ImStr;
use crate::imgui::Ui;
/// Builder for a list box widget
#[derive(Copy, Clone, Debug)]
#[must_use]
pub struct ListBox<'a> {
label: &'a ImStr,
size: crate::imgui_sys::ImVec2,
}
impl<'a> ListBox<'a> {
/// Constructs a new list box builder.
#[doc(alias = "ListBoxHeaderVec2", alias = "ListBoxHeaderInt")]
pub const fn new(label: &'a ImStr) -> ListBox<'a> {
ListBox {
label,
size: crate::imgui_sys::ImVec2::zero(),
}
}
/// Sets the list box size based on the given width and height
/// If width or height are 0 or smaller, a default value is calculated
/// Helper to calculate the size of a listbox and display a label on the right.
/// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty"
///
/// Default: [0.0, 0.0], in which case the combobox calculates a sensible width and height
#[inline]
pub const fn size(mut self, size: [f32; 2]) -> Self {
self.size = crate::imgui_sys::ImVec2::new(size[0], size[1]);
self
}
/// Creates a list box and starts appending to it.
///
/// Returns `Some(ListBoxToken)` if the list box is open. After content has been
/// rendered, the token must be ended by calling `.end()`.
///
/// Returns `None` if the list box is not open and no content should be rendered.
#[must_use]
pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ListBoxToken<'ui>> {
let should_render =
unsafe { crate::imgui_sys::igBeginListBox(self.label.as_ptr(), self.size) };
if should_render {
Some(ListBoxToken::new(ui))
} else {
None
}
}
/// Creates a list box and runs a closure to construct the list contents.
/// Returns the result of the closure, if it is called.
///
/// Note: the closure is not called if the list box is not open.
pub fn build<T, F: FnOnce() -> T>(self, ui: &Ui<'_>, f: F) -> Option<T> {
self.begin(ui).map(|_list| f())
}
}
create_token!(
/// Tracks a list box that can be ended by calling `.end()`
/// or by dropping
pub struct ListBoxToken<'ui>;
/// Ends a list box
drop { crate::imgui_sys::igEndListBox() }
);
/// # Convenience functions
impl<'a> ListBox<'a> {
/// Builds a simple list box for choosing from a slice of values
pub fn build_simple<T, L>(
self,
ui: &Ui,
current_item: &mut usize,
items: &[T],
label_fn: &L,
) -> bool
where
for<'b> L: Fn(&'b T) -> Cow<'b, ImStr>,
{
use crate::imgui::widget::selectable::Selectable;
let mut result = false;
let lb = self;
if let Some(_cb) = lb.begin(ui) {
for (idx, item) in items.iter().enumerate() {
let text = label_fn(item);
let selected = idx == *current_item;
if Selectable::new(&text).selected(selected).build(ui) {
*current_item = idx;
result = true;
}
}
}
result
}
}