arcdps_imgui\widget/list_box.rs
1use std::borrow::Cow;
2
3use crate::sys;
4use crate::Ui;
5
6/// Builder for a list box widget
7#[derive(Copy, Clone, Debug)]
8#[must_use]
9pub struct ListBox<T> {
10 label: T,
11 size: sys::ImVec2,
12}
13
14impl<T: AsRef<str>> ListBox<T> {
15 /// Constructs a new list box builder.
16 #[doc(alias = "ListBoxHeaderVec2", alias = "ListBoxHeaderInt")]
17 pub fn new(label: T) -> ListBox<T> {
18 ListBox {
19 label,
20 size: sys::ImVec2::zero(),
21 }
22 }
23
24 /// Sets the list box size based on the given width and height
25 /// If width or height are 0 or smaller, a default value is calculated
26 /// Helper to calculate the size of a listbox and display a label on the right.
27 /// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty"
28 ///
29 /// Default: [0.0, 0.0], in which case the combobox calculates a sensible width and height
30 #[inline]
31 pub fn size(mut self, size: [f32; 2]) -> Self {
32 self.size = sys::ImVec2::new(size[0], size[1]);
33 self
34 }
35 /// Creates a list box and starts appending to it.
36 ///
37 /// Returns `Some(ListBoxToken)` if the list box is open. After content has been
38 /// rendered, the token must be ended by calling `.end()`.
39 ///
40 /// Returns `None` if the list box is not open and no content should be rendered.
41 #[must_use]
42 pub fn begin<'ui>(self, ui: &Ui<'ui>) -> Option<ListBoxToken<'ui>> {
43 let should_render = unsafe { sys::igListBoxHeader_Vec2(ui.scratch_txt(self.label), self.size) };
44 if should_render {
45 Some(ListBoxToken::new(ui))
46 } else {
47 None
48 }
49 }
50 /// Creates a list box and runs a closure to construct the list contents.
51 /// Returns the result of the closure, if it is called.
52 ///
53 /// Note: the closure is not called if the list box is not open.
54 pub fn build<R, F: FnOnce() -> R>(self, ui: &Ui<'_>, f: F) -> Option<R> {
55 self.begin(ui).map(|_list| f())
56 }
57}
58
59create_token!(
60 /// Tracks a list box that can be ended by calling `.end()`
61 /// or by dropping
62 pub struct ListBoxToken<'ui>;
63
64 /// Ends a list box
65 drop { sys::igListBoxFooter() }
66);
67
68/// # Convenience functions
69impl<T: AsRef<str>> ListBox<T> {
70 /// Builds a simple list box for choosing from a slice of values
71 pub fn build_simple<V, L>(
72 self,
73 ui: &Ui<'_>,
74 current_item: &mut usize,
75 items: &[V],
76 label_fn: &L,
77 ) -> bool
78 where
79 for<'b> L: Fn(&'b V) -> Cow<'b, str>,
80 {
81 use crate::widget::selectable::Selectable;
82 let mut result = false;
83 let lb = self;
84 if let Some(_cb) = lb.begin(ui) {
85 for (idx, item) in items.iter().enumerate() {
86 let text = label_fn(item);
87 let selected = idx == *current_item;
88 if Selectable::new(&text).selected(selected).build(ui) {
89 *current_item = idx;
90 result = true;
91 }
92 }
93 }
94 result
95 }
96}